【洛谷P3928】SAC E#1 - 一道简单题 Sequence2

题目背景

小强和阿米巴是好朋友。

题目描述

小强喜欢数列。有一天,他心血来潮,写下了三个长度均为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.如果在第三行选,对于连续的一段在第三行选的数,必须满足方向相同(都小于等于上一个数或者都大于等于上一个数)

输入输出格式

输入格式:

输入包含4行。

第一行一个数n,表示数列长度。

第2、3、4行,每行n个整数,分别表示三个数列。

输出格式:

输出仅包含一个整数,即最长波动数列的长度。

输入输出样例

输入样例#1:
6
1 2 3 6 5 4
5 4 3 7 8 9
1 2 3 6 5 4
输出样例#1:
6

说明

对于20%的数据,n <= 10, m <= 1000

对于60%的数据,n <= 1000, m <= 1000

对于100%的数据, n <= 100000, m <= 1000000000

其中m = max|a[i]|

样例解释:

取第三行1 2 3(增),然后取第1行6(增),然后取第三行5 4(减),长度为6。

分析

做了这一题之后我感觉自己学了假的树状数组.....

这题开了8个树状数组来优化DP,其实也就两个一个维护前缀和,一个维护后缀和。

 

代码

60分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=3*100000+5;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int n,ans;
int a[maxn][30],dp[maxn][4];
int main()
{
    n=read();
    for(int i=1;i<=n;++i) a[i][0]=read();
    for(int i=1;i<=n;++i) a[i][1]=read();
    for(int i=1;i<=n;++i) a[i][2]=read(),a[i][3]=a[i][2];
    dp[1][0]=dp[1][1]=dp[1][2]=dp[1][3]=1;
    for(int i=2;i<=n;++i)
    for(int j=1;j<i;++j)
    for(int k=0;k<4;++k)
    {
        if(a[i][0]>=a[j][k]) dp[i][0]=max(dp[i][0],dp[j][k]+1);
        if(a[i][1]<=a[j][k]) dp[i][1]=max(dp[i][1],dp[j][k]+1);
        if(k!=3&&a[i][2]>=a[j][k]) dp[i][2]=max(dp[i][2],dp[j][k]+1);
        if(k!=2&&a[i][3]<=a[j][k]) dp[i][3]=max(dp[i][3],dp[j][k]+1);
    }
    for(int i=1;i<=n;++i)
    for(int k=0;k<4;++k)
        ans=max(ans,dp[i][k]);
    printf("%d\n",ans);
    return 0;
}
    

100分代码

由于用树状数组的话m有可能很大,所以要去重加离散化。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100000+5;
inline int read()
{
    register int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int n,m,tot,ans;
int a[maxn][5],t[maxn*3],c[9][maxn*3],f[maxn][5];
inline void update(int id,int x,int v){
    for( ;x<=m;x+=x&(-x))
        c[id][x]=max(c[id][x],v);
}
inline int query(int id,int x){
    register int res=0;
    for( ;x;x-=x&(-x))
        res=max(res,c[id][x]);
    return res;
}
int main()
{
    n=read();
    for(register int j=1;j<=3;++j)
        for(register int i=1;i<=n;++i)
            a[i][j]=read(),t[++tot]=a[i][j];
    sort(t+1,t+tot+1);
    m=unique(t+1,t+tot+1)-(t+1);
    for(register int j=1;j<=3;++j)
        for(register int i=1;i<=n;++i)
            a[i][j]=lower_bound(t+1,t+m+1,a[i][j])-t;
    for(register int i=1;i<=n;++i){
        f[i][1]=max(f[i][1],query(1,a[i][1])+1);
        f[i][1]=max(f[i][1],query(3,a[i][1])+1);
        f[i][1]=max(f[i][1],query(5,a[i][1])+1);
        f[i][1]=max(f[i][1],query(7,a[i][1])+1);
        
        f[i][3]=max(f[i][3],query(1,a[i][3])+1);
        f[i][3]=max(f[i][3],query(3,a[i][3])+1);
        f[i][3]=max(f[i][3],query(5,a[i][3])+1);
        
        f[i][2]=max(f[i][2],query(2,m-a[i][2]+1)+1);
        f[i][2]=max(f[i][2],query(4,m-a[i][2]+1)+1);
        f[i][2]=max(f[i][2],query(6,m-a[i][2]+1)+1);
        f[i][2]=max(f[i][2],query(8,m-a[i][2]+1)+1);
        
        f[i][4]=max(f[i][4],query(2,m-a[i][3]+1)+1);
        f[i][4]=max(f[i][4],query(4,m-a[i][3]+1)+1);
        f[i][4]=max(f[i][4],query(8,m-a[i][3]+1)+1);
        
        update(1,a[i][1],f[i][1]);
        update(2,m-a[i][1]+1,f[i][1]);
        
        update(3,a[i][2],f[i][2]);
        update(4,m-a[i][2]+1,f[i][2]);
        
        update(5,a[i][3],f[i][3]);
        update(6,m-a[i][3]+1,f[i][3]);
        
        update(7,a[i][3],f[i][4]);
        update(8,m-a[i][3]+1,f[i][4]);
        
        for(register int j=1;j<=4;++j){
            ans=max(ans,f[i][j]);
        }
    }
    printf("%d\n",ans);
    return 0;
}
    

 

posted @ 2017-10-07 22:39  沐灵_hh  阅读(262)  评论(0编辑  收藏  举报