zoukankan      html  css  js  c++  java
  • HDU 4747 Mex 递推/线段树

    题目链接:

    acm.hdu.edu.cn/showproblem.php?pid=4747

    Mex

    Time Limit: 15000/5000 MS (Java/Others)
    Memory Limit: 65535/65535 K (Java/Others)

    问题描述

    Mex is a function on a set of integers, which is universally used for impartial game theorem. For a non-negative integer set S, mex(S) is defined as the least non-negative integer which is not appeared in S. Now our problem is about mex function on a sequence.

    Consider a sequence of non-negative integers {ai}, we define mex(L,R) as the least non-negative integer which is not appeared in the continuous subsequence from aL to aR, inclusive. Now we want to calculate the sum of mex(L,R) for all 1 <= L <= R <= n.

    输入

    The input contains at most 20 test cases.
    For each test case, the first line contains one integer n, denoting the length of sequence.
    The next line contains n non-integers separated by space, denoting the sequence.
    (1 <= n <= 200000, 0 <= ai <= 10^9)
    The input ends with n = 0.

    输出

    For each test case, output one line containing a integer denoting the answer.

    样例输入

    3
    0 1 3
    5
    1 0 2 0 1
    0

    样例输出

    5
    24

    Hint

    For the first test case:
    mex(1,1)=1, mex(1,2)=2, mex(1,3)=2, mex(2,2)=0, mex(2,3)=0,mex(3,3)=0.
    1 + 2 + 2 + 0 +0 +0 = 5.

    题意

    mex(s)表示没有在集合s中出现的最小非负数,现在要求所有的mex(si)(si为由数列的一个子串组成的集合)的和。

    题解

    1、递推、 [参考]

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=0x3f3f3f3f3f3f3f3fLL;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    
    //start----------------------------------------------------------------------
    
    const int maxn=2e5+10;
    
    int n;
    int arr[maxn];
    //last[x]表示x这个数最晚出现的位置
    //full[x]表示完全覆盖0到x的且左边界最靠右的区间
    int last[maxn],full[maxn];
    //dp[i]表示以i结尾的所有区间的贡献
    LL dp[maxn];
    
    void init(){
        clr(dp,0);
        clr(full,0);
        clr(last,0);
    }
    
    int main() {
        while(scf("%d",&n)==1&&n){
            init();
            for(int i=1;i<=n;i++) scf("%d",&arr[i]);
            LL ans=0;
            for(int i=1;i<=n;i++){
                dp[i]=dp[i-1];
                if(arr[i]<n){
                    int v=arr[i];
                    int pre=last[v];
                    last[v]=i;
                    for(int j=v;j<n;j++){
                        if(j) full[j]=min(last[j],full[j-1]);
                        else full[j]=i;
                        if(full[j]>pre) dp[i]+=full[j]-pre;
                        else break;
                    }
                }
                ans+=dp[i];
            }
            prf("%lld
    ",ans);
        }
        return 0;
    }
    
    //end-----------------------------------------------------------------------
    

    2、线段树
    初始时线段树上第i个节点存mex(a[1]~a[i])(注意!这个存在单调性!)。
    然后我们依次从a[1]开始删除,直到删到a[n-1]。 如果删掉a[1],那么我们对于原本mex值就小于等于a[1]的节点自然没有影响,而对于mex>a[1]且其它位置不存在a[1]的元素,删掉这个a[1]之后它的mex值就会等于a[1],所以我们只要用线段树update一下区间[第一个mex值大于a[1](根据单调性在线段树上二分查找)的位置,下一个值等于a[1]的位置-1]。

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=0x3f3f3f3f3f3f3f3fLL;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    
    //start----------------------------------------------------------------------
    
    const int maxn=2e5+10;
    
    LL sumv[maxn<<2];
    int mexv[maxn<<2],setv[maxn<<2];
    int arr[maxn],b[maxn];
    bool vis[maxn];
    int mp[maxn],last[maxn];
    int n;
    
    void pushdown(int o,int l,int r) {
        if(setv[o]>=0) {
            sumv[lson]=(mid-l+1)*setv[o];
            mexv[lson]=setv[o];
    
            sumv[rson]=(r-mid)*setv[o];
            mexv[rson]=setv[o];
    
            setv[lson]=setv[rson]=setv[o];
            setv[o]=-1;
        }
    }
    
    void maintain(int o) {
        sumv[o]=sumv[lson]+sumv[rson];
        mexv[o]=max(mexv[lson],mexv[rson]);
    }
    
    void build(int o,int l,int r) {
        if(l==r) {
            sumv[o]=mexv[o]=b[l];
        } else {
            build(lson,l,mid);
            build(rson,mid+1,r);
            maintain(o);
        }
    }
    
    int _v,_pos;
    void query(int o,int l,int r) {
        if(l==r) {
            if(_v>=mexv[o]) _pos=n+1;
            else _pos=l;
        } else {
            pushdown(o,l,r);
            if(_v>=mexv[lson]) query(rson,mid+1,r);
            else query(lson,l,mid);
            maintain(o);
        }
    }
    
    int ql,qr,_v2;
    void update(int o,int l,int r) {
        if(ql<=l&&r<=qr) {
            sumv[o]=(r-l+1)*_v2;
            mexv[o]=_v2;
            setv[o]=_v2;
        } else {
            pushdown(o,l,r);
            if(ql<=mid) update(lson,l,mid);
            if(qr>mid) update(rson,mid+1,r);
            maintain(o);
        }
    }
    
    void init() {
        clr(vis,0);
        clr(setv,-1);
        for(int i=0; i<=n; i++) mp[i]=last[i]=n+1;
    }
    
    int main() {
        while(scf("%d",&n)==1&&n) {
            init();
            int mex=0;
            for(int i=1; i<=n; i++) {
                int x;
                scf("%d",&x);
                arr[i]=x;
                if(x<n) vis[x]=1;
                while(vis[mex]) mex++;
                b[i]=mex;
            }
    
            for(int i=n; i>=1; i--) {
                if(arr[i]<n) {
                    mp[i]=last[arr[i]]-1;
                    last[arr[i]]=i;
                }
            }
    
    //        for(int i=1;i<=n;i++) prf("%d ",b[i]); puts("");
            build(1,1,n);
    
            LL ans=sumv[1];
    //        bug(ans);
            for(int i=1; i<n; i++) {
    
                if(arr[i]>=n) {
                    ans+=sumv[1];
                } else {
                    _v=arr[i];
                    query(1,1,n);
    //                prf("%d,%d
    ",_pos,mp[i]);
    
                    if(_pos<=mp[i]){
                        ql=_pos,qr=mp[i];
                        _v2=arr[i];
                        update(1,1,n);
                    }
                    ans+=sumv[1];
                }
    //            bug(ans);
            }
    
            prf("%lld
    ",ans);
        }
        return 0;
    }
    
    //end-----------------------------------------------------------------------  
    

    Notes

    枚举区间: dp[i]表示以i为右边界的所有区间的贡献。

  • 相关阅读:
    lnmp配置Yii2规则
    vue中前进刷新、后退缓存,列表缓存和回到原位置
    vue 或者传统h5移动端input被输入法键盘挡住解决方法
    uni-app知识
    typescript
    flow
    js点击按钮分别实现全屏以及退出全屏的方法
    vue.config.js配置本地,测试,开发环境变量
    git常用指令
    Git指令
  • 原文地址:https://www.cnblogs.com/fenice/p/5855898.html
Copyright © 2011-2022 走看看