zoukankan      html  css  js  c++  java
  • [2020多校A层11.30] 选举

    有一个长度为 (N) 的字符串 (S[1dots N]),它仅由 (C)(T) 两种字母组成。

    现在有 (Q) 个查询,每个查询包含两个整数 (L)(R) ,表示:设新字符串 (S'=S[Ldots R]) ,至少在 (S') 中要删除多少个字符,才能保证:对于 (S') 的每一个前缀与每一个后缀,其 (C) 的数量都不小于 (T) 的数量。

    (N,Qle 5 imes 10^5)


    还不错的一道题,只不过考试的时候没来得及仔细想。

    考虑怎么求出这个答案,设 (C=1,T=-1) ,我们可以从前往后扫前缀和 (s) ,如果 (s) 遇到 (-1) 变成负数了,那么一定要删掉当前的;做完这个操作之后再在当前删完的区间中做后缀和判断。

    这样贪心一定是对的,因为前缀和是负数的话一定删最后面的,后缀和同理。

    我们再进一步观察这个做法,发现删除的一个 (-1) 既可以在前缀被删除,也可以在后缀被删除,那么就相当于存在一个分解点,分界点前的最小前缀和是要删去的 (-1) 个数,分界点后的最小后缀和是要删除的 (-1) 个数(取绝对值),并且要最大化。那么就会有下面这个形式化的式子:

    [ans=max_{i=l}^{r}(max_{j=l}^{i-1}(s_{l-1}-s_j)+max_{k=i+1}^r(s_k-s_r)) ]

    化简可以得到:

    [ans=(max_{k=l+1}^rmax_{j=k}^rs_k-s_j)-(s_r-s_{l-1}) ]

    发现前面就是一个最大子段和,各种数据结构维护都可以。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    const int N = 5e5;
    using namespace std;
    int n,q,s[N + 5];
    char ch[N + 5];
    struct node
    {
        int pre,suf,sm,ans;
    };
    node operator +(node a,node b)
    {
        a.ans = max(a.ans,b.ans);
        a.ans = max(a.ans,a.suf + b.pre);
        a.suf = max(a.suf + b.sm,b.suf);
        a.pre = max(a.pre,a.sm + b.pre);
        a.sm += b.sm;
        return a;
    }
    struct Seg
    {
        node s[N * 4 + 5];
        #define zrt k << 1
        #define yrt k << 1 | 1
        void build(int k,int l,int r)
        {
            if (l == r)
            {
                if (ch[l] == 'C')
                    s[k].pre = s[k].suf = s[k].sm = s[k].ans = 1;
                else
                    s[k].sm = -1;
                return;
            }
            int mid = l + r >> 1;
            build(zrt,l,mid);
            build(yrt,mid + 1,r);
            s[k] = s[zrt] + s[yrt];
        }
        node query(int k,int l,int r,int x,int y)
        {
            if (l >= x && r <= y)
                return s[k];
            int mid = l + r >> 1;
            if (x > mid)
                return query(yrt,mid + 1,r,x,y);
            if (y <= mid)
                return query(zrt,l,mid,x,y);
            return query(zrt,l,mid,x,y) + query(yrt,mid + 1,r,x,y);
        }
    }tree;
    int main()
    {
        //freopen("elections.in","r",stdin);
        //freopen("elections.out","w",stdout);
        scanf("%d",&n);
        scanf("%s",ch + 1);
        for (int i = 1;i <= n;i++)
        {
            s[i] = s[i - 1];
            if (ch[i] == 'C')
                s[i]++;
            else
                s[i]--;
        }
        tree.build(1,1,n);
        int l,r;
        scanf("%d",&q);
        while (q--)
        {
            scanf("%d%d",&l,&r);
            printf("%d
    ",tree.query(1,1,n,l,r).ans - (s[r] - s[l - 1]));
        }
        return 0;
    }
    
  • 相关阅读:
    js笔记4
    js笔记3
    js笔记2
    js笔记1
    前端笔记13
    (7)第3章的开始
    (6)第2章的尾巴~
    (5)自定义数据结构再探
    我的学习方法(6)
    (4)自定义数据结构初探
  • 原文地址:https://www.cnblogs.com/sdlang/p/14062471.html
Copyright © 2011-2022 走看看