1 条题解
-
0
题目大意:
找到一个最长的子序列,使得相邻两个数的大小满足给定条件。
做法:
首先,可以很显然的想出一个二维的动态规划, 表示以第 位结尾的序列长度对 取模是 ,很明显不能通过。考虑变成一维, 表示以 结尾的序列的最大长度。先思考贪心,到第 个位置,肯定是长度越长的越优,因为长度长的下一位可以选的位置是从 到 ,但是长度短的要选到长度长的的长度就需要选几位,等到相同长度时,下一位可以选的就少了,所以肯定是不优的。有了这个贪心,动态规划转移的情况就只剩三种了。用两个树状数组维护大于和小于两种情况的最大值,再用数组维护剩下等于的情况的最大值就可以了,转移这三种情况取最大值即可。最后记录下结尾的位置,从后往前推出序列即可,复杂度可以通过。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+5,M=5e5+5; int n,k,a[M],b[M],up,dp[M],p[N]; struct Tree{ int tree[N]; int lowbit(int x){ return x&(-x); } void add(int x,int y){ for(int i=x;i<=up;i+=lowbit(i)){ tree[i]=max(tree[i],y); } } int query(int x){ int res=0; for(int i=x;i>=1;i-=lowbit(i)){ res=max(res,tree[i]); } return res; } }t1,t2; void js(int x){ if(dp[x]==1){ cout<<a[x]<<" "; return ; } int o=(dp[x]-2)%k+1; o=b[o]; for(int i=x-1;i>=1;i--){ if(dp[i]+1==dp[x]&&((o==0&&a[i]==a[x])||(o==1&&a[i]>a[x])||(o==-1&&a[i]<a[x]))){ js(i); break; } } cout<<a[x]<<" "; } int main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n>>k; for(int i=1;i<=n;i++){ cin>>a[i]; up=max(up,a[i]); } for(int i=1;i<=k;i++){ char x; cin>>x; if(x=='<'){ b[i]=-1; }else if(x=='='){ b[i]=0; }else{ b[i]=1; } } int ans=0,g=0; for(int i=1;i<=n;i++){ dp[i]=max(t1.query(a[i]-1),max(t2.query(up-a[i]),p[a[i]]))+1; int o=(dp[i]-1)%k+1; if(b[o]==0){ p[a[i]]=max(p[a[i]],dp[i]); }else if(b[o]==-1){ t1.add(a[i],dp[i]); }else{ t2.add(up-a[i]+1,dp[i]); } ans=max(ans,dp[i]); if(dp[i]==ans){ g=i; } } cout<<ans<<"\n"; js(g); cout<<"\n"; return 0; }
- 1
信息
- ID
- 3755
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者