题意:给一个有n(n<=100000)个数字的序列,其中要么是0要么是正整数,0可以变成任意整数,问该序列的最长上升子序列。
比赛的时候被这题卡了三个小时,貌似因为数据水,有的人错误的代码都过了,自己真的菜啊…………
思路:贪心的思路应该是基于这个结论:lca不一定包含所有0,但是所有0组成的某个序列一定是lca其中的一个。大题证明思路:如果有一个lca不含所有的0,那么我们可以把这个lca中靠近原序列中的0的某个数换成0,数次这样操作,这个lca就变成了包含所有0的lca。
那么正如题解说的,可以把所有的0拿出来,每个非0的数减去前面出现的0的个数,然后对这些数计算lca,加上0的总数就ok了,这样得到的lca包含了所有0,且保证了其他非0数组成的lca最长
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
#define MS(x,y) memset(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define lowbit(x) (x&(-x))
typedef long long LL;
inline void fre1(){freopen("1010.in","r",stdin);/*freopen("output.txt","w",stdout);*/}
inline void fre2(){fclose(stdin);/*fclose(stdout);*/}
const int MAXN=100000+5;
const double EPS=1e-8;
int n,x,tot,sum;
int a[MAXN],dp[MAXN];
int main()
{
int T,kase=0;
scanf("%d",&T);
while(T--){
bool flag=false;
scanf("%d",&n);
tot=0,sum=0;
for(int i=1;i<=n;++i){
scanf("%d",&x);
if(x) a[++tot]=x-sum,flag=true;
else ++sum;
}
MS(dp,0);
dp[1]=a[1];
int ans=1;
for(int i=2;i<=tot;++i){
int p=lower_bound(dp+1,dp+1+ans,a[i])-dp;
dp[p]=a[i];
ans=max(ans,p);
}
if(!flag) ans=0;
printf("Case #%d: %d\n",++kase,ans+sum);
}
return 0;
}