题目链接:
acm.hdu.edu.cn/showproblem.php?pid=4747
Mex
问题描述
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\n",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\n",_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\n",ans); } return 0; } //end-----------------------------------------------------------------------
Notes
枚举区间: dp[i]表示以i为右边界的所有区间的贡献。
来源:https://www.cnblogs.com/fenice/p/5855898.html