洛谷 P3928 Sequence

题目描述

小强喜欢数列。有一天,他心血来潮,写下了三个长度均为n的数列。

阿米巴也很喜欢数列。但是他只喜欢其中一种,波动数列。

阿米巴把他的喜好告诉了小强。小强便打算找出这三个数列内的最长波动数列。

也就是说,如果我们将三个数列记做a[n][3],他必须要构造一个二元组序列:<p[i], q[i]>,使得对于任何 i>1 有:

p[i] > p[i-1]

若q[i] = 0,a[p[i]][q[i]] >= a[p[i-1]][q[i-1]]

若q[i] = 1,a[p[i]][q[i]] <= a[p[i-1]][q[i-1]]

若q[i] = 2,只要保持段内同向即可(就是对于连续的一段q[i]=2,要么都有a[p[i]][q[i]] >= a[p[i-1]][q[i-1]],要么都有a[p[i]][q[i]] <= a[p[i-1]][q[i-1]])。

小强希望这个二元组序列尽可能长。

提示:当q[i] != q[i-1]时,数列的增减性由q[i]而非q[i-1]决定。

清晰版题目描述

小强拿到一个3×n的数组,要在每一列选一个数(或者不选),满足以下条件:

1.如果在第一行选,那它必须大于等于上一个数

2.如果在第二行选,那么必须小于等于上一个数

3.如果在第三行选,对于连续的一段在第三行选的数,必须满足方向相同(都小于等于上一个数或者都大于等于上一个数)

  清晰版描述简直坑人。。。

  思路非常明显,智障dp。状态转移方程不读错题的话简直秒出。之后考虑转移优化。显然,一个范围内的最大值可以用线段树维护,当然要事先吧数据离散化。代码很简单,二十分钟就可以敲完,然后我就爆了一个钟的空间23333

#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000000+10
typedef long long LL;
int n,tot=0,ans=0,pos[4][MAXN],dp[5][MAXN],tr[5][MAXN*52];
LL a[5][MAXN],b[MAXN*4];
void pushup(int t,int k){tr[t][k]=max(tr[t][k<<1],tr[t][k<<1|1]);}
void build(int t,int k,int l,int r){
    tr[t][k]=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(t,k<<1,l,mid);
    build(t,k<<1|1,mid+1,r);
}
void update(int t,int k,int l,int r,int p,int val){
    if(l==r&&l==p){
        tr[t][k]=val;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)update(t,k<<1,l,mid,p,val);
    else update(t,k<<1|1,mid+1,r,p,val);
    pushup(t,k);
}
int query(int t,int k,int l,int r,int L,int R){
    if(l>=L&&r<=R)return tr[t][k];
    int mid=(l+r)>>1;
    if(R<=mid)return query(t,k<<1,l,mid,L,R);
    else if(L>mid)return query(t,k<<1|1,mid+1,r,L,R);
    else return max(query(t,k<<1,l,mid,L,R),query(t,k<<1|1,mid+1,r,L,R));
}
int main(){
    //freopen("data.in","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=3;i++)
        for(int j=1;j<=n;j++){
            scanf("%lld",&a[i][j]);
            b[++tot]=a[i][j];        
        }
    sort(b+1,b+tot+1);
    tot=unique(b+1,b+tot+1)-b,tot--;
    for(int i=1;i<=4;i++)build(i,1,1,tot);
    for(int i=1;i<=3;i++)
        for(int j=1;j<=n;j++)
            pos[i][j]=lower_bound(b+1,b+tot+1,a[i][j])-b;
        
    for(int i=1;i<=4;i++)update(i,1,1,tot,pos[i==4?3:i][1],1),dp[i][1]=1;
    for(int i=2;i<=n;i++){
        for(int k=1;k<=4;k++)dp[k][i]=1;
        for(int k=1;k<=4;k++){    
            if(k==1)
                for(int j=1;j<=4;j++)
                    dp[k][i]=max(dp[k][i],query(j,1,1,tot,1,pos[1][i])+1);
            else if(k==2)
                for(int j=1;j<=4;j++)
                    dp[k][i]=max(dp[k][i],query(j,1,1,tot,pos[2][i],tot)+1);
            else if(k==3)
                for(int j=1;j<=3;j++)
                    dp[k][i]=max(dp[k][i],query(j,1,1,tot,pos[3][i],tot)+1);
            else
                for(int j=1;j<=4;j++)
                    if(j!=3)dp[k][i]=max(dp[k][i],query(j,1,1,tot,1,pos[3][i])+1);        
        }
        for(int k=1;k<=4;k++){
            update(k,1,1,tot,pos[k==4?3:k][i],dp[k][i]);
            ans=max(ans,dp[k][i]);
        }
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/NINGLONG/p/7647309.html