编程介的小学生 2017-11-18 16:56 采纳率: 20.5%
浏览 678
已结题

Mex

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.

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.

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

Sample Input
3
0 1 3
5
1 0 2 0 1
0

Sample Output
5
24

  • 写回答

1条回答 默认 最新

  • 银河曼巴 2018-07-23 14:03
    关注

    题目大意:定义mex(l,r)为S[l, r]中没出现的最小的非负数。求∑mex(i,j)∑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]为从以Si开头还没确定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开始考虑,如果只有一个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])。
    每处理完一个数,就得到一个∑s[i]∑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):

    复制代码
    #include
    #include
    #include
    #include
    using namespace std;
    typedef long long LL;

    #define ll x * 2
    #define rr x * 2 + 1

    const int MAXN = 200010;

    LL tree[MAXN * 4];
    int maxt[MAXN * 4], mint[MAXN * 4];
    int a[MAXN], n;

    int head[MAXN], lcnt;
    int pos[MAXN], next[MAXN];

    void init() {
    memset(head, 0, (n + 1) * sizeof(int));
    lcnt = 1;
    }

    void add_link(int x, int i) {
    pos[lcnt] = i; next[lcnt] = head[x]; head[x] = lcnt++;
    }

    void build(int x, int left, int right) {
    if(left == right) tree[x] = maxt[x] = mint[x] = n - left + 1;
    else {
    int mid = (left + right) >> 1;
    if(left <= mid) build(ll, left, mid);
    if(mid < right) build(rr, mid + 1, right);
    tree[x] = tree[ll] + tree[rr];
    maxt[x] = max(maxt[ll], maxt[rr]);
    mint[x] = min(mint[ll], mint[rr]);
    }
    }

    void update(int x, int left, int right, int a, int b, int val) {
    if(a <= left && right <= b && mint[x] >= val) {
    tree[x] = LL(val) * (right - left + 1);
    maxt[x] = mint[x] = val;
    }
    else {
    if(right == left) return ;
    int mid = (left + right) >> 1;
    if(maxt[x] == mint[x]) {
    maxt[ll] = mint[ll] = maxt[x];
    tree[ll] = LL(mid - left + 1) * maxt[x];
    maxt[rr] = mint[rr] = maxt[x];
    tree[rr] = LL(right - (mid + 1) + 1) * maxt[x];
    }
    if(a <= mid && maxt[ll] > val) update(ll, left, mid, a, b, val);
    if(mid < b && maxt[rr] > val) update(rr, mid + 1, right, a, b, val);
    tree[x] = tree[ll] + tree[rr];
    maxt[x] = max(maxt[ll], maxt[rr]);
    mint[x] = min(mint[ll], mint[rr]);
    }
    }

    LL solve() {
    LL ret = 0;
    build(1, 1, n);
    for(int i = 0; i <= n && tree[1]; ++i) {
    int last = 0;
    for(int p = head[i]; p; p = next[p]) {
    update(1, 1, n, last + 1, pos[p], n - pos[p] + 1);
    last = pos[p];
    }
    update(1, 1, n, last + 1, n, 0);
    ret += tree[1];
    }
    return ret;
    }

    int main() {
    while(scanf("%d", &n) != EOF && n) {
    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    init();
    for(int i = n; i > 0; --i) if(a[i] <= n) add_link(a[i], i);
    cout<<solve()<<endl;
    }
    }

    评论

报告相同问题?

悬赏问题

  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题