zoukankan      html  css  js  c++  java
  • BZOJ 4553 [Tjoi2016&Heoi2016]序列

    题目

    佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。

    现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可。

    注意:每种变化最多只有一个值发生变化。

    在样例输入1中,所有的变化是

    1 2 3
    2 2 3
    1 3 3
    1 1 3
    1 2 4

    选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:

    3 3 3

    3 2 3

    选择子序列为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求。

    思路

    显然的dp

    dp[i]表示到第i个元素的时候,最优情况。

    如果dp[i]可以有dp[j]转移而来,那么j需要满足以下两个条件:

    1. (a[j]<=mi[i])
    2. (mx[j]<=a[i])

    然后考虑CDQ分治优化dp:

    显然上面的转移是二维的,所以只要分别用排序和树状数组消维就行了。

    代码

    #include<bits/stdc++.h>
    #define M 100005
    using namespace std; 
    int n,m;
    struct node{
        int s,mi,mx,ans,id;
    }A[M];
    bool cmps(node a,node b){return a.s<b.s;}
    bool cmpmi(node a,node b){return a.mi<b.mi;}
    bool cmp(node a,node b){return a.id<b.id;}
    struct BIT{
        int C[M];
        void add(int x,int d){
            x++;
            while(x<=M+1){
                C[x]=max(C[x],d);
                x+=(x&-x);
            }
        }
        int sum(int x){
            x++;int s=0;
            while(x){
                s=max(s,C[x]);
                x-=(x&-x);
            }
            return s;
        }
        void clear(int x){
            x++;
            while(x<=M+1){
                C[x]=0;
                x+=(x&-x);
            }
        }
    }T;
    void CDQ(int l,int r){
        if(l==r)return;
        int mid=(l+r)>>1;
        CDQ(l,mid);sort(A+mid+1,A+r+1,cmpmi);
        for(int i=l,j=mid+1;j<=r;j++){
            while(i<=mid&&A[i].s<=A[j].mi){
                T.add(A[i].mx,A[i].ans);i++;
            }
            A[j].ans=max(A[j].ans,T.sum(A[j].s)+1);
        }
        sort(A+mid+1,A+r+1,cmp);
        for(int i=l;i<=mid;i++)T.clear(A[i].mx);
        CDQ(mid+1,r);
        sort(A+l,A+r+1,cmps);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)A[i].mi=1e9,A[i].mx=-1e9,A[i].ans=1;
        for(int i=1,x;i<=n;i++)scanf("%d",&x),A[i].s=x,A[i].mi=min(A[i].mi,x),A[i].mx=max(A[i].mx,x),A[i].id=i;
        for(int i=1,x,y;i<=m;i++){
            scanf("%d%d",&x,&y);
            A[x].mx=max(A[x].mx,y);
            A[x].mi=min(A[x].mi,y);
        }
        CDQ(1,n);
        int ans=0;
        for(int i=1;i<=n;i++)ans=max(ans,A[i].ans); 
        printf("%d
    ",ans); 
        return 0;
    }
    
  • 相关阅读:
    操作系统
    Typora
    C++
    linux sftp 和scp 运用
    python GIL锁与多cpu
    django model 高级进阶
    django template 模板
    django view 视图控制之数据返回的视图函数
    django 创建管理员用户
    jango 模型管理数据model入门
  • 原文地址:https://www.cnblogs.com/zryabc/p/11231724.html
Copyright © 2011-2022 走看看