Problem Description
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.
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.
Input
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, 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.
Output
For each test case, output one line containing a integer denoting the answer.
題目大意:定義mex(l,r)為S[l, r]中沒出現的最小的非負數。求$ \sum mex(i,j) $,0≤i≤j≤n
思路:我總覺得自己思路有點奇葩大家將就着看。。
考慮每一個子段S[l,n],如果S[l,n]的第一個0出現在 i ( i 在 l 和 n 之間),那么S[l, i-1]的mex值都為0。
按這個思路搞,考慮S[i]為從以S[i](1≤i≤n)開頭還沒確定mex值的子段數,那么初始化為S[i] = n-i+1(數組從1開始計數)
/* 補充說明一下s[i]
就是什么都沒做的時候,比如s[1] = n
然后只有一個0在位置3
那么就可以確定mex[1,1]和mex[1,2]為0了,mex[1,i],i≥3都至少為1,但還不知道他們會不會大於1,所以s[1] = n - 2
然后只有一個1在位置7
那么就可以確定mex[1,i],3≤i<7,都為1(都只有0沒有1),而i≥7的mex[1,i]都至少為2(他們都含有0和1),所以s[1] = n - 7
s[i]就是從i開始的mex[i,x]在第 p 階段還沒有確定值只知道有s[i]個mex[i,x]至少大於p
然后只有一個0在位置3
那么就可以確定mex[1,1]和mex[1,2]為0了,mex[1,i],i≥3都至少為1,但還不知道他們會不會大於1,所以s[1] = n - 2
然后只有一個1在位置7
那么就可以確定mex[1,i],3≤i<7,都為1(都只有0沒有1),而i≥7的mex[1,i]都至少為2(他們都含有0和1),所以s[1] = n - 7
s[i]就是從i開始的mex[i,x]在第 p 階段還沒有確定值只知道有s[i]個mex[i,x]至少大於p
*/
那么從0開始考慮,如果只有一個0,出現在了x位置,那么s[1,x-1]的子段的mex值都為0,所以S[i] = n-x+1(i < x),大於 x 的 s[i]都為0(大於x的子段不存在0,他們的最小非負數都為0)
如果有兩個0,那么設第一個0位置為x,第二個0位置為y,那么s[i] = n-x+1(i < x),s[i] = n - y + 1(x≤i<y),大於 y 的 s[i]都為0
有多個0也一樣,處理完0之后,得到的sum{s[i]}就是最少為1的mex子段數
然后從1開始往上處理,對某一個數在位置x,s[i] = min(n-x+1, s[i])。
每處理完一個數,就得到一個$ \sum s[i] $ ,依次可以得到最少為2的mex字段數,最少為3的mex字段數……把這些都加起來就是答案。
說得有點抽象……舉個例子1 0 2 0 1
初始化s[1] = 5, s[2] = 4, s[3] = 3, s[4] = 2, s[5] = 1
那么處理數字0,s[1] = 4, s[2] = 4, s[3] = 2, s[4] = 2, s[5] = 0, ans = 12
處理數字1,s[1] = 4, s[2] = 1, s[3] = 1, s[4] = 1, s[5] = 0, ans = 12 + 7 = 19
處理數字2,s[1] = 3, s[2] = 1, s[3] = 1, s[4] = 0, s[5] = 0, ans = 19 + 5 = 24
那么可以看出這個是區間賦值,采用線段樹處理可以在O(nlogn)的時間內解出答案。
代碼(1000MS):

1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 typedef long long LL; 7 8 #define ll x * 2 9 #define rr x * 2 + 1 10 11 const int MAXN = 200010; 12 13 LL tree[MAXN * 4]; 14 int maxt[MAXN * 4], mint[MAXN * 4]; 15 int a[MAXN], n; 16 17 int head[MAXN], lcnt; 18 int pos[MAXN], next[MAXN]; 19 20 void init() { 21 memset(head, 0, (n + 1) * sizeof(int)); 22 lcnt = 1; 23 } 24 25 void add_link(int x, int i) { 26 pos[lcnt] = i; next[lcnt] = head[x]; head[x] = lcnt++; 27 } 28 29 void build(int x, int left, int right) { 30 if(left == right) tree[x] = maxt[x] = mint[x] = n - left + 1; 31 else { 32 int mid = (left + right) >> 1; 33 if(left <= mid) build(ll, left, mid); 34 if(mid < right) build(rr, mid + 1, right); 35 tree[x] = tree[ll] + tree[rr]; 36 maxt[x] = max(maxt[ll], maxt[rr]); 37 mint[x] = min(mint[ll], mint[rr]); 38 } 39 } 40 41 void update(int x, int left, int right, int a, int b, int val) { 42 if(a <= left && right <= b && mint[x] >= val) { 43 tree[x] = LL(val) * (right - left + 1); 44 maxt[x] = mint[x] = val; 45 } 46 else { 47 if(right == left) return ; 48 int mid = (left + right) >> 1; 49 if(maxt[x] == mint[x]) { 50 maxt[ll] = mint[ll] = maxt[x]; 51 tree[ll] = LL(mid - left + 1) * maxt[x]; 52 maxt[rr] = mint[rr] = maxt[x]; 53 tree[rr] = LL(right - (mid + 1) + 1) * maxt[x]; 54 } 55 if(a <= mid && maxt[ll] > val) update(ll, left, mid, a, b, val); 56 if(mid < b && maxt[rr] > val) update(rr, mid + 1, right, a, b, val); 57 tree[x] = tree[ll] + tree[rr]; 58 maxt[x] = max(maxt[ll], maxt[rr]); 59 mint[x] = min(mint[ll], mint[rr]); 60 } 61 } 62 63 LL solve() { 64 LL ret = 0; 65 build(1, 1, n); 66 for(int i = 0; i <= n && tree[1]; ++i) { 67 int last = 0; 68 for(int p = head[i]; p; p = next[p]) { 69 update(1, 1, n, last + 1, pos[p], n - pos[p] + 1); 70 last = pos[p]; 71 } 72 update(1, 1, n, last + 1, n, 0); 73 ret += tree[1]; 74 } 75 return ret; 76 } 77 78 int main() { 79 while(scanf("%d", &n) != EOF && n) { 80 for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); 81 init(); 82 for(int i = n; i > 0; --i) if(a[i] <= n) add_link(a[i], i); 83 cout<<solve()<<endl; 84 } 85 }