首页 > 代码库 > [补档][Poi2010]Monotonicity 2

[补档][Poi2010]Monotonicity 2

题目

给出N个正整数a[1..N],再给出K个关系符号(>、<或=)s[1..k]。
选出一个长度为L的子序列(不要求连续),要求这个子序列的第i项和第i+1项的的大小关系为s[(i-1)mod K+1]。
求出L的最大值。

INPUT

第一行两个正整数,分别表示N和K (N, K <= 500,000)。
第二行给出N个正整数,第i个正整数表示a[i] (a[i] <= 10^6)。
第三行给出K个空格隔开关系符号(>、<或=),第i个表示s[i]。

OUTPUT

一个正整数,表示L的最大值。

SAMPLE

INPUT

7 3
2 4 3 1 3 5 3
< > =

OUTPUT

6

解题报告

考试时连最最最简单的DP都没想出来,就打了个DFS- -
正解:
我们先考虑只有一种符号的情况,比如说考虑<,那么不就变成了求最长上升子序列吗。
同样的,我们扩展至三种符号:
技术分享
 1 for(int i=1;i<=n;i++){
 2     f[i]=1;
 3     for(int j=1;j<=i-1;j++){
 4         int tmp(f[j]%k+1);
 5         if(op[tmp]===&&a[j]==a[i]&&f[j]+1>f[i])
 6             f[i]=f[j]+1;
 7         if(op[tmp]==>&&a[j]>a[i]&&f[j]+1>f[i])
 8             f[i]=f[j]+1;
 9         if(op[tmp]==<&&a[j]<a[i]&&f[j]+1>f[i])
10             f[i]=f[j]+1;
11     }
12 }
View Code
这就是最最最简单的DP,然而我们知道,这玩意是O(n2)的复杂度,显然会T,那么我们就需要优化一下了。
我们发现,转移时有O(n)的复杂度来找最大值,那么我们想,是否可以把这个过程优化呢?自然可以,我们的目的在于找到权值符合条件的最大f值,所以,我们需要一个新的东西来完成它:

权值线段树

这是一个神奇的数据结构- -,好吧,也不怎么神奇,它在这道题里是以权值为下标,存入该点最优解的一种线段树,它就可以完成这个伟大的任务啦。
我们需要3棵树(其实2棵也可以,相等的那个用数组模拟即可实现,只是我比较懒- -),每一棵树存以该符号为后面所接符号的权值的最优解(好绕啊- -),这样我们在找的时候,取出每棵树中符合权值条件的最优解,三解进行比较,选出最优以确定符号,继续转移并更新相应的线段树即可。
(我语文表达能力好弱啊)
技术分享
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 using namespace std;
  5 inline int read(){
  6     int sum(0);
  7     char ch(getchar());
  8     for(;ch<0||ch>9;ch=getchar());
  9     for(;ch>=0&&ch<=9;sum=sum*10+(ch^48),ch=getchar());
 10     return sum;
 11 }
 12 inline char init(){
 13     char ch(getchar());
 14     for(;ch!==&&ch!=>&&ch!=<;ch=getchar());
 15     return ch;
 16 }
 17 inline int my_max(int a,int b){
 18     return a>b?a:b;
 19 }
 20 int n,k;
 21 int a[500001],op[500001];
 22 int tr_d[4000001],tr_x[4000001],tr_e[4000001];
 23 int ad_d[4000001],ad_x[4000001],ad_e[4000001];
 24 inline void pushup_d(int i){
 25     tr_d[i]=my_max(tr_d[i<<1],tr_d[i<<1|1]);
 26 }
 27 inline void pushup_x(int i){
 28     tr_x[i]=my_max(tr_x[i<<1],tr_x[i<<1|1]);
 29 }
 30 inline void pushup_e(int i){
 31     tr_e[i]=my_max(tr_e[i<<1],tr_e[i<<1|1]);
 32 }
 33 inline void pushdown_d(int i){
 34     if(ad_d[i]){
 35         ad_d[i<<1]=ad_d[i];
 36         ad_d[i<<1|1]=ad_d[i];
 37         tr_d[i<<1]=ad_d[i];
 38         tr_d[i<<1|1]=ad_d[i];
 39         tr_d[i]=ad_d[i];
 40         ad_d[i]=0;
 41     }
 42 }
 43 inline void pushdown_x(int i){
 44     if(ad_x[i]){
 45         ad_x[i<<1]=ad_x[i];
 46         ad_x[i<<1|1]=ad_x[i];
 47         tr_x[i<<1]=ad_x[i];
 48         tr_x[i<<1|1]=ad_x[i];
 49         tr_x[i]=ad_x[i];
 50         ad_x[i]=0;
 51     }
 52 }
 53 inline void pushdown_e(int i){
 54     if(ad_e[i]){
 55         ad_e[i<<1]=ad_e[i];
 56         ad_e[i<<1|1]=ad_e[i];
 57         tr_e[i<<1]=ad_e[i];
 58         tr_e[i<<1|1]=ad_e[i];
 59         tr_e[i]=ad_e[i];
 60         ad_e[i]=0;
 61     }
 62 }
 63 inline void update_d(int ll,int rr,int c,int l,int r,int i){
 64     if(ll<=l&&r<=rr){
 65         ad_d[i]=c;
 66         tr_d[i]=c;
 67         return;
 68     }
 69     pushdown_d(i);
 70     int mid((l+r)>>1);
 71     if(ll<=mid)
 72         update_d(ll,rr,c,l,mid,i<<1);
 73     if(rr>mid)
 74         update_d(ll,rr,c,mid+1,r,i<<1|1);
 75     pushup_d(i);
 76 }
 77 inline void update_x(int ll,int rr,int c,int l,int r,int i){
 78     if(ll<=l&&r<=rr){
 79         ad_x[i]=c;
 80         tr_x[i]=c;
 81         return;
 82     }
 83     pushdown_x(i);
 84     int mid((l+r)>>1);
 85     if(ll<=mid)
 86         update_x(ll,rr,c,l,mid,i<<1);
 87     if(rr>mid)
 88         update_x(ll,rr,c,mid+1,r,i<<1|1);
 89     pushup_x(i);
 90 }
 91 inline void update_e(int ll,int rr,int c,int l,int r,int i){
 92     if(ll<=l&&r<=rr){
 93         ad_e[i]=c;
 94         tr_e[i]=c;
 95         return;
 96     }
 97     pushdown_e(i);  
 98     int mid((l+r)>>1);
 99     if(ll<=mid)
100         update_e(ll,rr,c,l,mid,i<<1);
101     if(rr>mid)
102         update_e(ll,rr,c,mid+1,r,i<<1|1);
103     pushup_e(i);
104 }
105 inline int query_d(int ll,int rr,int l,int r,int i){
106     if(ll>rr)
107         return 0;
108     if(ll<=l&&r<=rr)
109         return tr_d[i];
110     pushdown_d(i);
111     int mid((l+r)>>1);
112     int ret(0);
113     if(ll<=mid)
114         ret=my_max(ret,query_d(ll,rr,l,mid,i<<1));
115     if(rr>mid)
116         ret=my_max(ret,query_d(ll,rr,mid+1,r,i<<1|1));
117     return ret;
118 }
119 inline int query_x(int ll,int rr,int l,int r,int i){
120     if(ll>rr)
121         return 0;
122     if(ll<=l&&r<=rr)
123         return tr_x[i];
124     pushdown_x(i);  
125     int mid((l+r)>>1);
126     int ret(0);
127     if(ll<=mid)
128         ret=my_max(ret,query_x(ll,rr,l,mid,i<<1));
129     if(rr>mid)
130         ret=my_max(ret,query_x(ll,rr,mid+1,r,i<<1|1));
131     return ret;
132 }
133 inline int query_e(int ll,int rr,int l,int r,int i){
134     if(ll>rr)
135         return 0;
136     if(ll<=l&&r<=rr)
137         return tr_e[i];
138     pushdown_e(i);
139     int mid((l+r)>>1);
140     int ret(0);
141     if(ll<=mid)
142         ret=my_max(ret,query_e(ll,rr,l,mid,i<<1));
143     if(rr>mid)
144         ret=my_max(ret,query_e(ll,rr,mid+1,r,i<<1|1));
145     return ret;
146 }
147 int f[500001];
148 int mx(0);
149 int main(){
150     n=read(),k=read();
151     for(int i=1;i<=n;i++)
152         a[i]=read(),mx=my_max(mx,a[i]);
153     for(int i=1;i<=k;i++){
154         char ch(init());
155         if(ch==>)
156             op[i]=1;
157         if(ch==<)
158             op[i]=2;
159         if(ch===)
160             op[i]=3;
161     }
162     f[1]=1;
163     if(op[1]==1)
164         update_d(a[1],a[1],f[1],1,mx,1);
165     if(op[1]==2)
166         update_x(a[1],a[1],f[1],1,mx,1);
167     if(op[1]==3)
168         update_e(a[1],a[1],f[1],1,mx,1);
169     for(int i=2;i<=n;i++){
170         int now(a[i]);
171         int ans_d(query_d(now+1,mx,1,mx,1));
172         int ans_x(query_x(1,now-1,1,mx,1));
173         int ans_e(query_e(now,now,1,mx,1));
174         int ans(my_max(my_max(ans_d,ans_x),ans_e));
175         f[i]=ans+1;
176         int o(op[ans%k+1]);//cout<<i<<‘ ‘<<f[i]<<‘ ‘<<o<<endl;
177         if(o==1)
178             update_d(now,now,f[i],1,mx,1);
179         if(o==2)
180             update_x(now,now,f[i],1,mx,1);
181         if(o==3)
182             update_e(now,now,f[i],1,mx,1);
183     }
184     int mxx(0);
185     for(int i=1;i<=n;i++)
186         mxx=my_max(mxx,f[i]);
187     printf("%d",mxx);
188 }
View Code
写的极其丑- -,毕竟三颗线段树乱搞
凑合着看吧,其实理解了之后,一颗线段树,加不同的域,对传的参数进行处理,就可以达到三颗线段树的效果

[补档][Poi2010]Monotonicity 2