Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 731 Accepted Submission(s): 236
我直接附上标准题解吧。。当时是看出这是最长下降跟最长上升序列的求和的,只是因为没相处nlogn算法,最终没有做出来。 今天终于AC掉了。 刚开始考虑的时候,还是没有考虑到
5
5 5 5 5 5 这种需要过滤掉重复的方法,导致WA了很多次,后来多开了一个数组保留才AC掉。
标准题解是:
Problem E. Deque考虑题目的一个简化版本:使双端队列单调上升。对于序列 A 和队列 Q,找到队列中最早出现的数字Ax,则Ax将 Q 分成的两个部分分别是原序列中以Ax开始的最长上升和最长下降序列,答案即为这两者之和的最大值。而对于本题,由于存在相同元素,所以只要找到以Ax为起点的最长不下降序列和最长不上升序列的和,然后减去两个里面出现Ax 次数的最小值即可。
我的代码是:
/* * @author ipqhjjybj * @date 20130723 */ #include <cstdio> #include <cstdlib> #include <cstring> #define MAXN 100005 #define clr(x,k) memset((x),(k),sizeof(x)) #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) int n; int a[MAXN]; int d_p[MAXN]; //存储递减序列的数字 int d_f[MAXN]; int n_d_f[MAXN];//相同数字出现次数 int i_p[MAXN]; //存储递增序列的数字 int i_f[MAXN]; int n_i_f[MAXN];//相同数字出现次数 int find_dec(int l,int r,int x){ int i=l,j=r,mid; while(i<=j){ mid=(i+j)>>1; if(d_p[mid]<=x) i=mid+1; else j=mid-1; }return i; } int find_inc(int l,int r,int x){ int i = l,j=r,mid; while(i<=j){ mid=(i+j)>>1; if(i_p[mid]>=x) i=mid+1; else j=mid-1; }return i; } int main(){ //freopen("1005.in","r",stdin); int z; scanf("%d",&z); while(z--){ clr(n_i_f,0),clr(n_d_f,0); scanf("%d",&n); for(int i = 1;i <= n;i++) scanf("%d",&a[i]); int ans=1; int d_ans=1; d_p[1]=a[n]; d_f[n]=1; n_d_f[1]=1; int i_ans=1; i_p[1]=a[n]; i_f[n]=1; n_i_f[1]=1; for(int i=n-1;i>0;i--){ int t1=find_dec(1,d_ans,a[i]); if(t1>d_ans)d_ans++; d_p[t1]=a[i]; n_d_f[t1]=(t1>1&&d_p[t1-1]==a[i])?n_d_f[t1-1]+1:1; d_f[i]=t1; int t2=find_inc(1,i_ans,a[i]); if(t2>i_ans)i_ans++; i_p[t2]=a[i]; n_i_f[t2]=(t2>1&&i_p[t2-1]==a[i])?n_i_f[t2-1]+1:1; i_f[i]=t2; //printf("m_t1=%d m_t2=%d\n",m_t1,m_t2); int temp = t1+t2-min(n_d_f[t1],n_i_f[t2]); ans = max(ans,temp); } printf("%d\n",ans); } return 0; }
325MS过掉。。
附上标准程序
#include "iostream" #include "cstring" #include "cstdio" #include "vector" #include "algorithm" #include "map" using namespace std; const int N = 100010; int a[N]; int num_up[N],num_down[N]; int dp_up[N],dp_down[N]; int n; void getdp(int dp[],int num[]) { dp[n]=1; vector<int> v; v.push_back(a[n]); vector<int>::iterator iter; for(int i=n-1;i>=1;i--){ int sz=v.size(); if(a[i]>v[sz-1]){ v.push_back(a[i]); dp[i]=sz+1; num[i]=1; }else if(a[i]==v[sz-1]){ iter=upper_bound(v.begin(),v.end(),a[i]); dp[i]=iter-v.begin()+1; v.push_back(a[i]); pair<vector<int>::iterator,vector<int>::iterator> bounds; bounds=equal_range(v.begin(),v.end(),a[i]); num[i]=bounds.second-bounds.first; }else{ iter=upper_bound(v.begin(),v.end(),a[i]); dp[i]=iter-v.begin()+1; *iter=a[i]; pair<vector<int>::iterator,vector<int>::iterator> bounds; bounds=equal_range(v.begin(),v.end(),a[i]); num[i]=bounds.second-bounds.first; } } } void debug(int a[]) { for(int i=1;i<=n;i++){ printf("%d ",a[i]); } printf("\n"); } int main(void) { int T; scanf("%d",&T); while(T--){ int ans=0; scanf("%d",&n); map<int,int> mp; mp.clear(); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } getdp(dp_up,num_up); for(int i=1;i<=n;i++){ a[i]=-a[i]; } getdp(dp_down,num_down); for(int i=1;i<=n;i++){ mp[a[i]]++; ans=max(ans,dp_down[i]+dp_up[i]-min(num_up[i],num_down[i])); } printf("%d\n",ans); } return 0; }
标准程序用了986MS。。。可能我的程序优化的还好点吧。。。
总而言之是水平不够。。当时没想出nlogn算法。。