[Poi2010]Monotonicity 2题解
Posted Forever_goodboy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Poi2010]Monotonicity 2题解相关的知识,希望对你有一定的参考价值。
题目描述
给出N个正整数a[1..N],再给出K个关系符号(>、<或=)s[1..k]。
选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。
求出L的最大值。
输入
第一行两个正整数,分别表示N和K (N, K <= 500,000)。
第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6)。
第三行给出K个空格隔开关系符号(>、<或=),第i个表示s[i]。
输出
一个正整数,表示L的最大值。
样例输入
7 3
2 4 3 1 3 5 3
< > =
样例输出
6
solution:
考试的时候打了没有优化的dp,两层for循环枚举前面每一个满足条件的,因为求f[i]时,f[j]的最长长度已经求出,符号确定,可以直接转移,
f[i]=max(f[i],f[j]+1); (i>j&&a[i]、a[j]满足s[tail]),很好想,但是会T掉
优化的话其实刚才提到转移f[i]时f[j]长度已知,我们知道f[j]和它下一个数的关系,那我们可以用每个权值建三棵线段树,每一棵数中存的是a[i]对应的f[i],查询时我们可以用当前a[i]到三棵树中进行查询,如果是大于号的树,则找到1到a[i]-1中权值最大的a[j]此时满足a[j]<a[i],则f[i]可以被f[j]转移;等于号则找到一个权值相同的区间;小于号找a[i]+1到max;
将当前f[i]求出后我们就知道了它和它下一个数的符号了,此时便把它插入到相应符号的线段树里维护即可
复杂度,查询O(1),插入O(log106)
最坏应该是O(nlogn)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 int read() { 7 int s=0,f=1; 8 char ch=getchar(); 9 while(ch>‘9‘||ch<‘0‘) { 10 if(ch==‘-‘) 11 f=-1; 12 ch=getchar(); 13 } 14 while(ch>=‘0‘&&ch<=‘9‘) { 15 s=(s<<1)+(s<<3)+(ch^48); 16 ch=getchar(); 17 } 18 return s*f; 19 } 20 int a[500005],n,k,f[500005],opt[500005],maxx; 21 char s; 22 int tree[1000006*4][4]; 23 void pushup(int x,int op) { 24 tree[x][op]=max(tree[x<<1][op],tree[x<<1|1][op]); 25 } 26 void update(int i,int L,int R,int op,int num,int a) { 27 if(L==R) { 28 tree[i][op]=max(tree[i][op],num); 29 return ; 30 } else { 31 int mi=(L+R)>>1; 32 if(a<=mi) { 33 update(i*2,L,mi,op,num,a); 34 } else { 35 update(i*2+1,mi+1,R,op,num,a); 36 } 37 pushup(i,op); 38 } 39 } 40 int query(int i,int L,int R,int l,int r,int op) { 41 if(l>r){ 42 return 0; 43 } 44 if(l<=L&&r>=R) { 45 return tree[i][op]; 46 } 47 int mi=(L+R)>>1; 48 int ans=0; 49 if(l<=mi) { 50 ans=max(ans,query(i*2,L,mi,l,r,op)); 51 } 52 if(mi<r) { 53 ans=max(ans,query(i*2+1,mi+1,R,l,r,op)); 54 } 55 return ans; 56 } 57 int main() { 58 //freopen("mot.in","r",stdin); 59 //freopen("mot.out","w",stdout); 60 n=read(); 61 k=read(); 62 for(int i=1; i<=n; i++) { 63 a[i]=read(); 64 if(a[i]>maxx){ 65 maxx=a[i]; 66 } 67 } 68 for(int i=1; i<=k; i++) { 69 scanf("%c",&s); 70 char ch=getchar(); 71 if(s==‘>‘) { 72 opt[i]=1; 73 } 74 if(s==‘=‘) { 75 opt[i]=2; 76 } 77 if(s==‘<‘) { 78 opt[i]=3; 79 } 80 } 81 int ans=0; 82 /*for(int i=1;i<=n;i++){ 83 f[i]=1; 84 update(1,1,maxx,opt[1],1,a[i]); 85 }*/ 86 for(int i=1; i<=n; i++) { 87 int ans1=query(1,1,maxx,a[i]+1,maxx,1)+1; 88 int ans2=query(1,1,maxx,a[i],a[i],2)+1; 89 int ans3=query(1,1,maxx,1,a[i]-1,3)+1; 90 /*if(a[i]==1){ 91 cout<<ans1<<" "<<ans2<<" "<<ans3<<endl; 92 }*/ 93 f[i]=max(f[i],max(ans1,max(ans2,ans3))); 94 ans=max(ans,f[i]); 95 update(1,1,maxx,opt[(f[i]-1)%k+1],f[i],a[i]); 96 //cout<<(f[i]-1)%k+1<<" "<<opt[(f[i]-1)%k+1]<<" "<<f[i]<<endl; 97 } 98 printf("%d\n",ans); 99 return 0; 100 }
以上是关于[Poi2010]Monotonicity 2题解的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ2090/2089[Poi2010]Monotonicity 2 动态规划+线段树