zoukankan      html  css  js  c++  java
  • [Poi2010]Monotonicity 2 (线段树优化DP)

    题目描述

    给出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]转移

  • 相关阅读:
    Unbuntu--安装VMware Tools
    方法引用的基本使用
    Stream流
    Stream流的常用方法
    枚举
    编程式路由导航
    向路由组件传递数据
    缓存路由组件
    嵌套路由
    基本路由
  • 原文地址:https://www.cnblogs.com/FOXYY/p/7257553.html
Copyright © 2011-2022 走看看