Mex-hdu4747(DP)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4747 

题目大意:给一个含有n个数的序列 ns[1~n],定义函数 mex(l,r)为区间 [l,r] 中未出现的最小的非负整数,求序列ns所有区间的 mex 和。

Sample Input

3
0 1 3
5
1 0 2 0 1
0

Sample Output

5
24
思路详见博客:https://blog.csdn.net/qq1965610770/article/details/80041940
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int ns[200010];        // 序列 
int pos[200010];    // pos[i] 表示现阶段 i 在序列 ns 中出现的最后一个位置 
int full[200010];    // 现在遍历到了 i ,full[j] 表示已经覆盖0~j的区间[x,i] 中 x 的最大值 
int main()
{
    int n;
    while(~scanf("%d",&n) && n)
    {
        int i,j;
        for(i=1;i<=n;i++)
            scanf("%d",&ns[i]);
        memset(pos,0,sizeof(pos));
        memset(full,0,sizeof(full));
        int last;
        ll tt=0,ans=0;
        for(i=1;i<=n;i++)
        {
            if(ns[i] < n)    //对长度为n的序列无影响 
            {
                last = pos[ns[i]];    //数 ns[i] 前一次出现的最后位置 
                pos[ns[i]] = i;        //更新 ns[i] 最后的位置 
                for(j=ns[i];j<n;j++)    //遍历会产生影响的数字 
                {
                    if(j)    full[j] = min(full[j-1],pos[j]);    //更新full[j] 为 full[j-1] 与 pos[i] 中较小(左)的位置 
                    else    full[j] = i;    //如果是 0 ,则更新 full[0] 为现在这个 ns[i]=0 的位置i 
                    if(full[j] > last)
                        tt += full[j]-last;    //累加对last之前的位置无影响 
                    else
                        break;
                }
            }
            ans += tt;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2019-03-01 16:28  里昂静  阅读(278)  评论(0编辑  收藏  举报