[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 }

 

posted @ 2017-07-29 07:13  Forever_goodboy  阅读(299)  评论(0编辑  收藏  举报