Longest Increasing Subsequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 232 Accepted Submission(s): 57
Problem Description Bobo has a sequence a1,a2,…,an.
Let f(x) be the length of longest *strictly* increasing subsequence after replacing all the occurrence of 0 with x.
He would like to find ∑ni=1i⋅f(i).
Note that the length of longest strictly increasing subsequence of sequence s1,s2,…,sm is the largest k
such that there exists 1≤i1<i2<⋯<ik≤m satisfying si1<si2<⋯<sik.
Input The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains an integer n.
The second line contains n integers a1,a2,…,an.
Output For each test case, print an integer which denotes the result.
## Constraint
* 1≤n≤105
* 0≤ai≤n
* The sum of n does not exceed 250,000.
Sample Input
21 131 0 364 0 6 1 0 3
Sample Output
31449
题意:
给你一个长度为n的序列,
x从1变到n,每一次变化后,都用x替换序列里面的0,求一遍最长严格上升子序列的长度len,将答案加上len*x
最后输出答案
解析:
首先我们可以知道每一次变化,len是有一个最小值的,这个最小值就是把序列中0全部去掉所求出来的最长严格上升子序列长度lenmin。并且每一次变化最多只能让len在最小值的基础上+1,因为我们变化的只有一个数,所以在最长严格上升子序列中这个数最多只会有一次,所以每一次变化len的长度要么是[lenmin,lenmin+1]
然后上官方题解
设 fi, gi 分别表⽰以点 i 开始、结束的 LIS ⻓度,L 是原来的 LIS ⻓度。对于每个 i,找出它下⼀个 0 后⾯的 aj 满⾜ fi + gj = L,那么当 x 在[ai + 1, aj − 1] 的区间内时,答案是 L + 1.
根据官方题解,剩下的就是在得到f[],g[]下,怎么求满足条件的i,j使得fi+gj=L
当一个i,在他的下一个0后面有很多满足条件jk(k=1,2,..)使得a[i]<a[j]且fi+gj=L,每一对得到的区间是[ai+1,ajk-1](k=1,2,..),则有[ai+1,aj1-1],[ai+1,aj2-1],[ai+1,aj3-1],....,x的值在这些区间都是会对答案产生贡献的,观察发现起始这些区间有很多是包含的关系。
例如aj1<aj2,aj2>aj3>aj4>....,即aj2是最大值,则起始这些区间都被包含于[ai+1,aj2-1]。所以只有找每一个i,在他的下一个0后面有很多满足条件的j中,a[j]最大的那个j就可以了。将x属于[ai + 1, aj − 1]的情况的len+1
这样我们就可以从后往前扫,根据0来分段,复杂度只要O(n)即可
这里被自己的代码坑到了,数组定义的是longlong ,带初始化的时候用int来memset,因为这个原因卡了一天....
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long int ll;
#define MAXN 100010
ll n,len;
ll dp[MAXN];
ll a[MAXN],g[MAXN];
ll f[MAXN],b[MAXN];
ll fz[MAXN];
vector<int> pz;
int inc[MAXN];
ll binary_search2(ll key,ll g[],ll left,ll right)
{
ll mid;
while(left<right)
{
mid=(left+right)>>1;
if(key>g[mid]) left=mid+1; //不加等号,严格上升
else right=mid;
}
return left;
}
ll binary_search1(ll key,ll g[],ll left,ll right)
{
ll mid;
while(left<right)
{
mid=(left+right)>>1;
if(key>=g[mid]) right=mid; //加等号,严格递减
else left=mid+1;
}
return right;
}
int main()
{
int t;
while(scanf("%lld",&n)!=EOF)
{
ll j;
int flag;
flag=0;
ll ans=0;
memset(inc,0,sizeof(ll)*(n+3)); //!
memset(fz,-1,sizeof(ll)*(n+3)); //!!
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
if(a[i]!=0) flag=1;
}
if(!flag)
{
printf("%lld\n",(1+n)*n/2);
continue;
}
pz.clear();
//非递减
len=0;
g[0]=-100;
for(int i=0;i<n;i++)
{
if(a[i]==0)
{
f[i]=0;
pz.push_back(i);
continue;
}
if(a[i]>g[len])
j=++len;
else
j=binary_search2(a[i],g,1,len+1);
//j=lower_bound(g+1,g+len+1,a[i])-g;
g[j]=a[i];
f[i]=j;
}
g[0]=MAXN;
len=0;
for(int i=n-1;i>=0;i--)
{
if(a[i]==0)
{
b[i]=0;
continue;
}
if(a[i]<g[len])
j=++len;
else
j=binary_search1(a[i],g,1,len+1);
g[j]=a[i];
b[i]=j;
}
ans+=(1+n)*n/2*len;
for(int i=pz.size()-1;i>=0;i--)
{
int en;
if(i==pz.size()-1) en=n;
else en=pz[i+1];
int beg;
if(i==0) beg=0;
else beg=pz[i-1];
for(j=pz[i];j<en;j++)
{
if(a[j]==0)
{
fz[0]=n+1;
}
else
{
if(fz[b[j]]<a[j]) fz[b[j]]=a[j];
}
}
for(j=beg;j<=pz[i];j++)
{
if(fz[len-f[j]]!=-1&&fz[len-f[j]]>a[j]+1)
{
inc[a[j]+1]+=1,inc[fz[len-f[j]]]-=1;
}
}
}
for(int i=1;i<=n;i++)
{
inc[i]+=inc[i-1];
if(inc[i]>0) ans+=(ll)i;
}
printf("%lld\n",ans);
}
return 0;
}
这个参考别人的代码,对求LIS进行代码量减少的一种
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long int ll;
#define MAXN 100010
ll n,len;
ll a[MAXN],g[MAXN];
ll f[MAXN],b[MAXN];
vector<int> pz;
ll fz[MAXN];
int inc[MAXN];
int main()
{
int t;
while(scanf("%lld",&n)!=EOF)
{
ll j;
int flag;
flag=0;
ll ans=0;
memset(inc,0,sizeof(ll)*(n+3));
memset(fz,-1,sizeof(ll)*(n+3));
/*memset(g,0,sizeof(int)*(n+3));
memset(a,-1,sizeof(int)*(n+3));
memset(b,0,sizeof(int)*(n+3));
memset(f,-1,sizeof(int)*(n+3));*/
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
if(a[i]!=0) flag=1;
}
if(!flag)
{
printf("%lld\n",(1+n)*n/2);
continue;
}
pz.clear();
//非递减
len=0;
g[0]=-100;
for(int i=0;i<n;i++)
{
if(a[i]==0)
{
f[i]=0;
pz.push_back(i);
continue;
}
if(a[i]>g[len])
j=++len;
else
//j=binary_search2(a[i],g,1,len+1);
j=lower_bound(g+1,g+len+1,a[i])-g;
g[j]=a[i];
f[i]=j;
}
g[0]=-MAXN;
len=0;
for(int i=n-1;i>=0;i--)
{
if(a[i]==0)
{
b[i]=0;
continue;
}
if(-a[i]>g[len])
j=++len;
else
//j=binary_search1(a[i],g,1,len+1);
j=lower_bound(g+1,g+len+1,-a[i])-g;
g[j]=-a[i];
b[i]=j;
}
ans+=(1+n)*n/2*len;
for(int i=pz.size()-1;i>=0;i--)
{
int en;
if(i==pz.size()-1) en=n;
else en=pz[i+1];
int beg;
if(i==0) beg=0;
else beg=pz[i-1];
for(j=pz[i];j<en;j++)
{
if(a[j]==0)
{
fz[0]=n+1;
}
else
{
if(fz[b[j]]<a[j]) fz[b[j]]=a[j];
}
}
for(j=beg;j<=pz[i];j++)
{
if(fz[len-f[j]]!=-1&&fz[len-f[j]]>a[j]+1)
{
inc[a[j]+1]+=1,inc[fz[len-f[j]]]-=1;
}
}
}
for(int i=1;i<=n;i++)
{
inc[i]+=inc[i-1];
if(inc[i]>0) ans+=(ll)i;
}
printf("%lld\n",ans);
}
return 0;
}