题目描述
给出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
提示
选出的子序列为2 4 3 3 5 3,相邻大小关系分别是< > = < >。
1 #include<cmath> 2 #include<ctime> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 # define maxn 500010 9 # define lson rt<<1,l,mid 10 # define rson rt<<1|1,mid+1,r 11 using namespace std; 12 int n,K; 13 int a[maxn]; 14 int hao[maxn],ord[maxn]; 15 int lim; 16 void init(){ 17 scanf("%d%d",&n,&K); 18 for(int i=1;i<=n;i++) scanf("%d",&a[i]),lim=max(lim,a[i]); 19 char s[2]; 20 for(int i=1;i<=K;i++){ 21 scanf("%s",&s); 22 if(s[0]=='<') hao[i]=1; 23 if(s[0]=='=') hao[i]=2; 24 if(s[0]=='>') hao[i]=3; 25 } 26 for(int i=1;i<=n;i++) 27 ord[i]=hao[(i-1)%K+1]; 28 } 29 int f[maxn]; 30 struct XDS{ 31 int mx[4000010]; 32 void add(int now,int w,int rt,int l,int r){ 33 //cout<<now<<" "<<w<<" "<<rt<<" "<<l<<" "<<r<<endl; 34 if(l==r){ 35 mx[rt]=max(mx[rt],w); 36 return; 37 } 38 int mid=(l+r)>>1; 39 if(now<=mid){ 40 add(now,w,lson); 41 } 42 if(now>mid){ 43 add(now,w,rson); 44 } 45 mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); 46 } 47 int find(int left,int right,int rt,int l,int r){ 48 if(left<=l && r<=right){ 49 return mx[rt]; 50 } 51 int mid=(l+r)>>1; 52 int ans=0; 53 if(left<=mid){ 54 ans=max(ans,find(left,right,lson)); 55 } 56 if(right>mid){ 57 ans=max(ans,find(left,right,rson)); 58 } 59 return ans; 60 } 61 }; 62 XDS da,xiao; 63 int deng[1000010]; 64 void fang(int now,int w,int od){ 65 // cout<<"now== "<<now<<" "<<w<<" "<<od<<endl; 66 if(od==1){ 67 da.add(now,w,1,0,lim); 68 } 69 if(od==3){ 70 xiao.add(now,w,1,0,lim); 71 } 72 if(od==2){ 73 deng[now]=max(deng[now],w); 74 } 75 } 76 int main(){ 77 //freopen("a.in","r",stdin); 78 //freopen("mot.in","r",stdin); freopen("mot.out","w",stdout); 79 init(); 80 for(int i=1;i<=n;i++){ 81 int x; 82 x=deng[a[i]]+1; 83 fang(a[i],x,ord[x]); 84 x=da.find(0,a[i]-1,1,0,lim)+1; 85 fang(a[i],x,ord[x]); 86 x=xiao.find(a[i]+1,lim,1,0,lim)+1; 87 fang(a[i],x,ord[x]); 88 } 89 int ans=0; 90 for(int i=0;i<=lim;i++){ 91 ans=max(deng[i],ans); 92 } 93 ans=max(ans,da.find(0,lim,1,0,lim)); 94 ans=max(ans,xiao.find(0,lim,1,0,lim)); 95 cout<<ans<<endl; 96 return 0; 97 98 }
这道题是一道DP,如果是同 f[i][k]=max(f[j-1][t]+1); 其中i表示位置,k表示符号,但是n^2的效率肯定过不了,所以用线段树优化,
造两棵线段树,都按a[i]为小标,一个是下一个为大于号的,一个是下一个为小于号的,维护在a[i]且符号一定是的f[i]最大值,至于等于号直接开一个数组就行了,在转移的时候,例如要找能放大于号的,那么就直接在对应的书中在[1,a[i]-1]找最大值就行了,再将新更新出来的插入对应的树种,但是在插入的时候,一定要保证先插入等于的,因为如果先插入大于或小于的,可能会更新出下一个符号是等于号的,但是在插入后,因为等于号a[i]就是从a[i]转移,所以可能将原来的a[i]处的f[i]更新,导致答案变大,但是大于小于号不用管顺序,因为他们不从a[i]转移