• 洛谷P3928 SAC E#1


    提交地址

    题目背景

    小强和阿米巴是好朋友。

    题目描述

    小强喜欢数列。有一天,他心血来潮,写下了三个长度均为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。

    思路:

      首先可以用dp作。

      把第三个序列,改成两条。除了这两条之间,这四条中任意两条之间可以互穿。(当然也可以在本序列上跳)

      每次转移都是,从4×(i-1)的矩阵中找序列值符合大小关系,且dp值最大的,来扩展。

      时间复杂度O(4*n^2)

    #include<cstdio>
    #include<queue>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #include<cstring>
    using namespace std;
    const int M=1e5+9;
    int a[M][5],f[M][5];
    int n,ans;
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)    scanf("%d",&a[i][1]);
        for(int i=1;i<=n;i++)    scanf("%d",&a[i][2]);
        for(int i=1;i<=n;i++)    scanf("%d",&a[i][3]),a[i][4]=a[i][3];
        
        f[1][1]=f[1][2]=f[1][3]=f[1][4]=1;
        
        for(int i=2;i<=n;i++)
        for(int j=1;j<i;j++)
        for(int k=1;k<=4;k++)
        {
            if(a[i][1]>=a[j][k]&&f[j][k]+1>f[i][1])    f[i][1]=f[j][k]+1;
            if(a[i][2]<=a[j][k]&&f[j][k]+1>f[i][2]) f[i][2]=f[j][k]+1;
            if(k!=4&&a[i][3]>=a[j][k]&&f[j][k]+1>f[i][3]) f[i][3]=f[j][k]+1;
            if(k!=3&&a[i][4]<=a[j][k]&&f[j][k]+1>f[i][4]) f[i][4]=f[j][k]+1;        
        }
        
        for(int i=1;i<=n;i++)
        for(int k=1;k<=4;k++)
        ans=max(ans,f[i][k]);
        
        cout<<ans;
    }
    60分代码 

      要想有话的话,就要用到树结构了,我用树状数组做的。(为啥? 因为快啊!)

      当然,要用到多个树状数组,因为要对四个序列中每个序列单独求,而且序列一个算大于,一个算小于。

      时间复杂度O(n*logn)

    #include<cstdio>
    #include<queue>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cmath>
    #include<cstring>
    using namespace std;
    const int M=1e5+9;
    int n,m,tot,ans;
    int a[M][5],t[M*4],c[10][M*3],f[M][5];
    int cnt;
    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)
    {
        int ans=0;
        for(;x;x-=x&(-x))
            ans=max(ans,c[id][x]);
        return ans;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=3;i++)
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[j][i]);
            t[++cnt]=a[j][i];
        }
        sort(t+1,t+cnt+1);
        m=unique(t+1,t+cnt+1)-(t+1);
        
        for(int i=1;i<=3;i++)
        for(int j=1;j<=n;j++)
            a[j][i]=lower_bound(t+1,t+m+1,a[j][i])-t;
        for(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(int j=1;j<=4;j++)
                ans=max(ans,f[i][j]);
        }
        cout<<ans<<endl;
        return 0;
    }
    100分
  • 相关阅读:
    树莓派3 之 启动 和 系统配置
    树莓派3 之 初次使用
    Python 资源大全中文版
    乔布斯:遗失的访谈
    CSS3j背景渐变,字体颜色渐变,以及兼容IE写法
    系统设计相关
    JSON格式要求
    VUE解决空格和空行报错的问题
    css3实现悬停波浪效果
    css3实现匀速无限滚动效果
  • 原文地址:https://www.cnblogs.com/CLGYPYJ/p/7672441.html
Copyright © 2020-2023  润新知