hdu 4604 动态规划
思路:这题的感觉就是最长上升子序列的升级版。首先对于最长上升子序列要用n*log(n)的算法才行,这个复杂度的算法可以从hdu1025得到启发。然后就是什么情况下最优问题了。对于序列中某个数i,找出其后面最长不下降子序列长度和最长不上升子序列长度,将这两个长度加起来,最大的就是我们要找到。但由于存在相同值,那么我么就要确定这两个子序列中值为i的个数最少的那个,用上面求得和减去它。
我的代码比较挫。
#include<iostream> #include<cstring> #include<cmath> #include<string> #include<cstdio> using namespace std; int ans[200010],list[100010],low[100010],more[100010],same[100010]; int main() { int t,n,i,j; scanf("%d",&t); while(t--) { scanf("%d",&n); memset(low,0,sizeof(low)); memset(more,0,sizeof(more)); memset(same,0,sizeof(same)); for(i=1;i<=n;i++) scanf("%d",&list[i]); int len; ans[1]=list[n]; low[n]=1; len=1; same[n]=1; int l,r,mid; for(i=n-1;i>=1;i--) { if(ans[len]>=list[i]) { ans[++len]=list[i]; low[i]=len; } else { l=1; r=len; while(l<=r) { mid=(l+r)>>1; if(ans[mid]>=list[i]) l=mid+1; else r=mid-1; } ans[l]=list[i]; low[i]=l; } l=1,r=len; while(l<=r) { mid=(l+r)>>1; if(ans[mid]>list[i]) l=mid+1; else r=mid-1; } same[i]=low[i]-r; } ans[1]=list[n]; len=1; more[n]=1; for(i=n-1;i>=1;i--) { if(ans[len]<=list[i]) { ans[++len]=list[i]; more[i]=len; } else { l=1; r=len; while(l<=r) { mid=(l+r)>>1; if(ans[mid]<=list[i]) l=mid+1; else r=mid-1; } ans[l]=list[i]; more[i]=l; } l=1,r=len; while(l<=r) { mid=(l+r)>>1; if(ans[mid]<list[i]) l=mid+1; else r=mid-1; } same[i]=min(more[i]-r,same[i]); } int Ans=0; for(i=1;i<=n;i++) Ans=max(Ans,low[i]+more[i]-same[i]); printf("%d\n",Ans); } return 0; }