题意:一串数求最长上升子序列(严格)其中0可以变成任意数
解析:根据求最长上升子序列 的原理,每次新的数如果大于a[len],就a[len++]=x否则找到一个比x大的且最小的数,替换成x,因为是严格递增的,如果该数在序列中已经有了就不用操作。根据这个规则,对0的处理是在a[len+1]=a[len]+1 a[i]=a[i-1]+1;
如果每个都要操作的话就会T,但是我们发现,这个操作其实就是把数组移了一位,所以我们就不用移动,直接记录加了多少次1就好了,而对于每次进来的X我们都减去z1
#include<bits/stdc++.h>
#define maxn 101111
using namespace std;
int a[maxn],b[maxn];
int Search(int num,int low,int high) {
int mid;
while(low<=high) {
mid=(low+high)/2;
if(num==b[mid]) return -1;
if(num>b[mid]) low=mid+1;
else high=mid-1;
}
return low;
}
int DP(int n) {
int i,len,pos;
int z0=0;
b[1]=a[1];
len=1;
// for(int j=1;j<=len;j++) {
// cout << b[j] <<" ";
// }
// cout << endl;
for(int i=2;i<=n;i++) {
if(a[i]==0) {
z0++;
continue;
}
a[i]-=z0;
if(a[i]>b[len]) {
len=len+1;
b[len]=a[i];
}
else {
pos=Search(a[i],1,len);
if(pos==-1) {
continue;
}
b[pos]=a[i];
}
// for(int j=1;j<=len;j++) {
// cout << b[j] <<" ";
// }
//cout << endl;
}
return len+z0;
}
int main()
{
int t,n;
int kase=0;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int ans=DP(n);
printf("Case #%d: %d\n",++kase,ans);
}
return 0;
}