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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }