• G. Three Occurrences(问有多少个子序列(连续)满足所有值只出现确切3次。)


    题:https://codeforces.com/contest/1418/problem/G

    题意:给定n(n<=5e5)的序列,问有多少个子序列(连续)满足所有值只出现确切3次。

    分析:总操作:枚举左端点,查看多少个满足的右端点;

       对于某个值,要么不出现,要么只出现3次,那么对于当前枚举的左端点的值a[l],合法区间肯定就是之前累计过的第2次出现到第3次出现的位置之间(不包含第3次出现的位置);

       那么设对于每个合法区间的右端点我们标记为0,那么答案就是0的个数;

       首先没出现一次都让[i,pos[ a[i] ].size()-1] ]内先假设不合法,那么到第2,第3次的时候加回-1让其为0变合法,统计0最小值个数。

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define MP make_pair
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    typedef long long ll;
    const int M=5e5+6;
    const int inf=0x3f3f3f3f;
    const ll INF=1e18;
    vector<int>pos[M];
    int a[M];
    struct SegTree{
        int tr[M<<2],cnt[M<<2],lz[M<<2];
        void up(int root){
            tr[root]=min(tr[root<<1],tr[root<<1|1]);
            cnt[root]=0;
            if(tr[root]==tr[root<<1])
                cnt[root]=cnt[root<<1];
            if(tr[root]==tr[root<<1|1])
                cnt[root]+=cnt[root<<1|1];
        }
        void pushdown(int root){
            if(lz[root]){
                tr[root<<1]+=lz[root];
                tr[root<<1|1]+=lz[root];
                lz[root<<1]+=lz[root];
                lz[root<<1|1]+=lz[root];
                lz[root]=0;
            }
        }
        void build(int root,int l,int r){
            lz[root]=0;
            if(l==r){
                tr[root]=0;
                cnt[root]=1;
                return ;
            }
            int midd=(l+r)>>1;
            build(lson);
            build(rson);
            up(root);
        }
        void update(int L,int R,int val,int root,int l,int r){
            if(L<=l&&r<=R){
                tr[root]+=val;
                lz[root]+=val;
                return ;
            }
            int midd=(l+r)>>1;
            pushdown(root);
            if(L<=midd)
                update(L,R,val,lson);
            if(R>midd)
                update(L,R,val,rson);
            up(root);
        }
        int query(int L,int R,int root,int l,int r){
            if(L<=l&&r<=R){
                return tr[root]==0 ? cnt[root] : 0;
            }
            pushdown(root);
            int midd=(l+r)>>1;
            int res=0;
            if(L<=midd)
                res=query(L,R,lson);
            if(R>midd)
                res+=query(L,R,rson);
            return res;
        }
    }t1;
    int getid(int u,int x){
        return pos[u][pos[u].size()-x];
    }
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        t1.build(1,1,n);
        for(int i=1;i<=n;i++)
            pos[i].pb(n+1);
        ll ans=0;
        for(int i=n;i>=1;i--){
            ///1位置
            if(pos[a[i]].size()>=4){///让之前2位置的合法区间无效
                t1.update(getid(a[i],3),getid(a[i],4)-1,1,1,1,n);
            }
            pos[a[i]].pb(i);
            ///2位置
            if(pos[a[i]].size()>=4){///抵消掉下方之前位置3的操作,让合法区间有效
                t1.update(getid(a[i],3),getid(a[i],4)-1,-1,1,1,n);
            }
            /*for(auto it:pos[a[i]])
                cout<<it<<' ';
            cout<<endl;*/
            ///3位置
            t1.update(i,getid(a[i],2)-1,1,1,1,n);///先假设区间无效
            ans+=t1.query(i,n,1,1,n);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    /***
    10 9
    10 9 8
    10 9 8 7
    10 6
    10 6 5
    10 9 8 7 4
    10 9 8 7 4 3
    10 9 8 7 4 3 2
    10 6 5 1
    ***/
    View Code
  • 相关阅读:
    How to solve problems
    【Python】区分List 和String
    【Python】内置方法pop
    【Python】安装配置Anaconda
    【Web crawler】print_all_links
    【Python】多重赋值之值互换
    BNF巴科斯-诺尔范式
    Svn与Git的区别
    python项目部署
    linux每日命令(3):which命令
  • 原文地址:https://www.cnblogs.com/starve/p/13711738.html
Copyright © 2020-2023  润新知