• codeforce刷题(六)


    G. Maximize the Remaining String

    由小写字母组成的字符串(s),每次从中选取重复的字母进行删除,直到该字符串中的每个字母都只出现一次。问:最终形成的字典序最大的字符串,比如(ababab),答案为(ba)

    (1 leq len(s) leq 200000)

    题解

    (s=a_1a_2a_3cdots a_n),最后的字符串为(s'),它的首字符在(s)中对应位置为(p),显然(p)之前的字符都被删除了,并且被删除的字符在(p)位置之后都出现过,根据这个性质,二分枚举(p)。假设子串(a_1a_2cdots a_p)中字典序最大的字符为(a_i):

    • (a_i > a_p),则字符(a_i)作为(s')的首字符,更新(s=a_{i + 1}a_{i+2}a_{i+3}cdots a_n) - ({a_i}),(减号表示删除前一个字符串中所有的后一个字符)
    • (a_i == a_p),则字符(a_i)作为(s')的首字符,更新(s=a_{p + 1}a_{p+2}a_{p+3}cdots a_n) - ({a_p})
    • (a_i < a_p),则字符(a_p)作为(s')的首字符,更新(s=a_{p + 1}a_{p+2}a_{p+3}cdots a_n) - ({a_p})

    (a_i > a_p)时,如果有多个(a_i),显然选择第一次出现的(a_i)更优

    通过不断的枚举(p)确定(s')中的每个字符,且枚举次数不大于26次。

    复杂度(O(26*n*log(n)))

    E. K-periodic Garland

    由0,1组成的字符串(s),如果(s)中任意相邻字符'1'之间的距离为(K),则该字符串是良好的。将 '0' ( ightarrow) '1' (或者 '1' ( ightarrow) '0') 称为一次操作,问最少几次操作后,能将(s)变成良好的?

    注意:'00'、'0100' 对任意的(K)都是良好的,(1 le K le len(s) le 1e6)

    题解

    记最终良好的字符串为(str),考虑(s)中从左至右第一个 '1' 出现的位置,记为(pos),显然,(str)中从左至右第一个 '1' 出现的位置不会小于(pos),那么可以求得以(pos)作为(str)中从左至右第一个 '1' 出现的位置且满足良好的最少操作次数。如果不是(pos),那么会不会是(s)中第一个 '1' 和 第二个 '1' 之间的某个位置(P)呢?假设(str)满足上述条件,以(P)位置作为(str)中第一个 '1' 出现的位置,这样做的话需要 (t) 次操作,而令(s[pos] ightarrow 0),既让(str)中第二个 '1' 作为第一个 '1',所需要的操作次数至多为 (t - 1),故这样的(P)显然不应该考虑。综上所述,我们可以枚举(str)的第一个'1' 出现的位置,复杂度(O(frac{n^2}{K}))。对数论稍微敏感一点儿就会发现对(K)的加法将这些位置划分为了(K)类,什么意思呢?假设(K = 3)

    (i)
    0 3 6 9 12 15
    1 4 7 10 13 16
    2 5 8 11 14 17
    3 6 9 12 15 18
    4 7 10 13 16 19

    如果计算出了(pos = 0)的答案,相当于也就计算出了(pos = 3,6,9,12)的答案。所以只需要计算(K)次,每次的复杂度为(O(frac{n}{K})),故总的复杂度为(O(n))

    //#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,no-stack-protector,fast-math")
    // cnt[j] := 以 j 位置作为 str 中第一个 ‘1’ 的位置且使得 s 变为 str 所需要的最少次数
    #include <bits/stdc++.h>
    #define IO ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
    using namespace std;
    
    const int maxn = 1e6 + 5;
    
    int t, n, k;
    
    int main()
    {   
        cin >> t;
        while (t--)
        {   
            cin >> n >> k;
            string s;
            cin >> s;
    
            vector<int> use(2 * n + 5, 0);
            vector<int> cnt(2 * n + 5, 0);
    
            int pos = -1;
            for (int i = n - 1; ~i; i--) if (s[i] == '1') {
                pos = i;
                break;
            }
    
            if (pos == -1) {
                cout << 0 << endl;
                continue;
            }
    
            for (int i = 0; i < pos; i++) cnt[i] = -1;
    
            use[n - 1] = (s[n - 1] == '1');
            for (int i = n - 2; ~i; i--) {
                if (s[i] == '1') use[i] = 1;
                use[i] += use[i + 1];
            }
    
            int ans = n << 1 + 1;
            for (int i = n - 1; ~i; i--) if (s[i] == '1') {
    
                int tp = 0;
    
                for (int j = i + k; ; j += k) {
    
                    tp += (use[j - k + 1] - use[j] + 1);
    
                    if (cnt[j] != -1) {
                        tp = tp - 1 + cnt[j];
                        if (use[i + 1]) tp = min(tp, use[i + 1]);     // 直接抹掉 i 位置之后的所有的 ‘1’,可能较优。例如 K = 1,s = 10001
                        break;
                    }
                    if (j >= n) break;
                }
                cnt[i] = tp;
                ans = min(ans, tp + use[0] - use[i]);
            }
            cout << ans << endl;
            /* code */
        }
        
        return 0;
    }
    

    wonderful, BFS

    给一个01矩阵(A_{m*n}),有(q)次询问:(x,y),问离((x,y))最近的 1 的曼哈顿距离。

    (1 leq n,m leq 1000)(1 leq q leq 1e5)

    题解

    加一个超级源点(s),与所有的 1 连接起来,然后以(s) 作为起点,BFS遍历图的同时更新距离即可。复杂度(O(nm))【单纯的记录一哈,orz

    queue < pair<int, int> > qe;
    
    void BFS() {
        memset(d, -1, sizeof(d));
        for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) if (mp[i][j]) {
            d[i][j] = 0;
            qe.push(make_pair(i, j));
        }
        while(!qe.empty()) {
            pair<int, int> p = qe.front();
            qe.pop();
            for (int i = 0; i < 4; i++) {
                int u = p.first + dx[i], v = p.second + dy[i];
                if (u < 0 || v < 0 || u >= n || v >= m || d[u][v] != -1) continue;
                d[u][v] = d[p.first][p.second] + 1;
                qe.push(make_pair(u, v));
            }
        }
    }
    

    1349C - Orac and Game of Life【好题】

    给一个长度为(n)的序列,每次选择一个区间([l,r])并将这个区间包含的元素都替换为该区间的中位数(按照大小关系排在中间的数)。问最终是否能将整个序列中的元素都替换为(k)

    (1 leq n leq 1e5)(1 leq a_i, k leq 1e9)

    题解

    • 原始序列不包含(k),显然无解

    • 如果原始序列中存在一个区间,其中位数为(k),则最终肯定能够将整个序列替换为(k)

    • 如果原始序列不存在上述区间呢?构造

    在原序列中直接找一个中位数为(k)的区间,想了很久都没想到一个好的办法。其实,着眼于细微之处,如果序列中存在相邻的两个数为(k,a_i)或者(a_i,k),有(a_i geq k),那么显然这是一个中位数为(k)的区间。如果不存在这样的相邻两个数,既对任意的(k),其左右相邻的两个数都小于(k)(a_i,k,a_j),都有(a_i < k)(a_j < k)),那么只需要将其中的任意一个((a_i)或者(a_j))替换为大于或者等于(k)的数就行,等价于找一个中位数大于或者等于(k)的区间。怎么找呢?【orz】其实只需要找到一个区间((a_e,a_{e+1},a_{e+2})),其中至少存在两个大于(k)的数就行。为什么只需要找长度为3区间呢?假设存在一个区间([l,r])其中位数为(p)(pgeq k),说明这个区间大于或者等于(p)的元素至少有(frac{r-l+1}{2} + 1)个,既大于或者等于(k)的数至少超过一半,显然,至少存在一个长度为3的区间其中位数必定大于或者等于(k)。证明的话,将区间划分成一个一个长度为3且不相交的区间,然后对最后剩下的一个区间分类讨论即可。如果找不到上述的长度为3且满足条件的区间,显然不可能将(a_i)或者(a_j)替换为大于或者等于(k)的数。

    1349A - Orac and LCM

    给一个长度为(n)的序列,求(gcd({lcm(a_i,a_j)|1 leq i,j leq n,i eq j}))

    (1 leq n,a_i leq 2e5)

    题解

    想到了枚举最终答案的约数,但等于圈圈。记最终答案为(ans)(p)表示质数,注意:如果(p^k | ans),那么至少存在(n-1)(a_i),有(p^k|a_i)

    反证法很好证明。知道这个特点之后怎么做呢?直接的思路依然是枚举,然而!求(n-1)(a_i)(gcd)不就找到了(p^k)吗,妙得一匹。记(gcd(a_i) = gcd({a} - {a_i})),那么(ans = lcm(gcd(a_1), gcd(a_2), gcd(a_3),cdots,gcd(a_n))).

    1346F - Dune II: Battle For Arrakis

    给一个棋盘(A_{n*m}),每个格子上有(a_{ij})枚棋子,记(cnt)为 将所有的棋子移到同一个格子上所需要的最少次数,一次只能将一枚棋子移动一步(上下左右)。现给(k)次修改:将(a_{ij} ightarrow b_{ij}),问每次修改后需要的最少次数,既(cnt)

    (1 leq n,m,k leq 1000)

    题解

    我的想法:研究修改后的最佳位置与先前最佳位置的关系,然并卵

    记最佳位置为((x,y)),有

    [egin{align} cnt =& sum_{i=1}^{n}sum_{j=1}^m(|x-i|+|y-j|)*a_{ij} \ =& (sum_{i=1}^nsum_{j=1}^m|x-i|*a_{ij}) + (sum_{i=1}^nsum_{j=1}^m|y-j|*a_{ij}) \ =& (sum_{i=1}^n(|x-i|*sum_{j=1}^ma_{ij})) + (sum_{j=1}^m(|y-j|*sum_{i=1}^na_{ij})) \ end{align} ]

    (A_i = sum_{j=1}^ma_{ij}), (B_j = sum_{i=1}^na_{ij}),有

    [cnt = sum_{i=1}^n|x-i|*A_i + sum_{j=1}^m|y-j|*B_j ]

    这是一个最优化问题,最小化(cnt),也就是分别最小化(sum_{i=1}^n|x-i|*A_i)(sum_{j=1}^m|y-j|*B_j)

    重点来了,最小化(sum_{i=1}^n|x-i|)比较好做,在最中间任取一个数就行。那多了一部分(A_i)该怎么做喃?在脑海中抽象一个模型,(x)轴上有一些球落在(x_i)处,记(x_i)处的球的个数为(A_i),然后有一个挡板(X)也在(x)轴上,问(X)的最佳位置,使得(sum_{i=1}^n|X-x_i|*A_i)最小。本质上与最小化(sum_{i=1}^n|x-i|)是同一个问题,所以(X)的位置依然是在最中间。同样的道理可以求得(y)的位置,知道((x,y))后就可以以(O(1000))的复杂度求得(cnt),最终复杂度为(O(max(n,m)*k))

    Palindrome(好题)

    给一个字符串(s),问它有多少个子串是好子串?一个子串被称为好子串(S)当且仅当它的长度为(3n-2)并且(S[i] = S[2n-i] = S[2n + i - 2])((1 leq i leq n)).

    (1 leq len(s) leq 500000)

    题解

    分析(S[i] = S[2n-i] = S[2n + i - 2]),可以发现对于一个长度为(3n-2)的好子串(S),有:

    • (S_{123...(2n-1)})是一个回文串并且中心为(n),半径为(n-1)
    • (S_{n(n+1)(n+2)...(3n-2)})是一个回文串并且中心为(2n-1),半径为(n-1)

    枚举前一个回文串的中心和半径,那么后一个回文串的中心和半径也就确定了。先用马拉车算法预处理出每个位置的回文半径(len[pos])。考虑已经枚举到(s)的第(i)位置,该位置的回文半径为(len[i]),如果(len[i+len[i]] geq len[i]),那么一个好子串就出现了,所以需要考虑以(i)位置为中心的所有回文子串,检查是否有合法的后一个回文串,既(len[i + len[i] - t] geq len[i] - t)((0 leq t leq len[i] - 1)).

    显然,不能直接暴力的检查 以(i)位置为中心的所有回文子串是否有合法的后一个回文串。观察上面这个不等式,移项:

    [len[i + len[i] - t] + t geq len[i] ~~~~~~~~~~~~~~~(0 leq t leq len[i] - 1) ]

    重点来了,令(p[i] = n - i + 1)((1leq i leq n)),那么合法的后一个回文串的个数就等于在(sum_{j=i+1}^{i+len[i]}((len[j] + p[j]-p[i+len[i]])geq len[i])),移项:

    [sum_{j = i + 1}^{i+len[i]}(len[j] + p[j] geq p[i + len[i]] + len[i]) ]

    求该和式等价于求一个区间([l,r])内,大于或者等于(K)的数有多少个?方法比较多,主席树,线段树,离线树状数组。

    /* 树状数组 */
    int n, m;
    int len[maxn << 1], b[maxn];
    
    char s[maxn << 1], s1[maxn];
    
    pair<int, int> a[maxn];
    
    void change() {
        for (int i = 1, t = 0; i <= n; i++) {
            s[++t] = '#';
            s[++t] = s1[i];
        }
        s[0] = '$', s[2 * n + 1] = '#', s[2 * n + 2] = '@', s[2 * n + 3] = '';
    
        n = 2 * n + 3;
    }
    
    void ma() {
        int id = 0;
        for (int i = 1; i <= n; i++) {
            int t = i > len[id] + id ? t = 0 : min(len[2 * id - i], id + len[id] - i);
            while(s[i + t] == s[i - t]) t++;
            len[i] = t - 1;
            if (id + len[id] <= i + len[i]) {
                id = i;
            }
        }
        id = 0;
        for (int i = 1; i <= n; i++) if (s[i] != '#') {
            len[++id] = len[i] / 2;
        }
    }
    
    struct query {
        int l, r, x;
        bool operator < (const query& i) const {
            if (x == i.x) return l < i.l;
            return x < i.x;
        }
    } q[maxn];
    
    int lowbit(int x) {
        return x & (-x);
    }
    
    void add(int i, int x) {
        while(i <= m) {
            b[i] += x;
            i += lowbit(i);
        }
    }
    
    int sum(int i) {
        int res = 0;
        while(i > 0) {
            res += b[i];
            i -= lowbit(i);
        }
        return res;
    }
    
    void solve() {
        int t = 0;
        for (int i = 1; i <= m; i++) if (len[i]) {
            q[t].l = i + 1;
            q[t].r = i + len[i];
            q[t++].x = len[i] + m - i - len[i] + 1;
        }
    
        for (int i = 1; i <= m; i++) {
            a[i].first = len[i] + m - i + 1;
            a[i].second = i;
        }
    
        sort(a + 1,  a + m + 1);
        sort(q, q + t);
    
        int j = 1;
        long long res = 0;
        for (int i = 0; i < t; i++) {
            while(a[j].first < q[i].x && j <= m) {
                add(a[j].second, 1);
                j++;
            }
            res += (q[i].r - q[i].l + 1) - (sum(q[i].r) - sum(q[i].l - 1));
        }
    
        printf("%lld
    ", res);
    }
    
    int main()
    {
        int cas;
        cin >> cas;
        while (cas--)
        {
            /* code */
            scanf("%s", s1 + 1);
        
            memset(len, 0, sizeof(len));
            memset(b, 0, sizeof(b));
    
            m = n = strlen(s1 + 1);
            change();
            ma();
        
            solve();
    
        }
        return 0;
    }
    

    1346E - Magic Tricks

    (n)个位置,每个位置上都有一个球。初始时,第(k)个位置上是一个特殊的球。现给出(m)次交换,记(t_i)表示(m)次交换后,特殊的球被交换到了(i)位置的最少 (fake ~ swap) 次数。一次交换被称为(fake ~ swap) 当且仅当这次交换什么都没做,既不发生交换。求出所有(t_i)((1 leq i leq n))

    (1 leq n,m leq 2e5)

    题解

    时间是线性的,令(dp[a][b]:=) (b)次交换后,特殊的球被交换到(a)位置的最少(fake ~ swap)次数,有:

    [假设第i次交换为:(u,v)\ dp[u][i] = min(dp[u][i - 1] + 1, dp[v][i - 1]) \ dp[v][i] = min(dp[v][i - 1] + 1, dp[u][i - 1]) ]

    1345D - Monopole Magnets

    给一个(n*m)的棋盘,每个格子都有一种颜色,黑色或者白色,然后将一些(N)(S)放入棋盘的格子中,一个格子可以放入多个,且(N)(S)可以放在同一个格子里面。求最少需要放入(N)的个数((S)的个数不限)使得满足如下三个条件:

    • 棋盘的每行每列至少有一个(S)
    • 对于黑色位置((i,j)),经过有限次操作后,至少存在一个(N)能到达这些位置。
    • 对于白色位置((i,j)),无论经过多少次的操作,都没有(N)能到达这些位置。

    一次操作:选取任意两个在同行或者同列,但不在同一个格子里面的(N)(S),保持(S)的位置不变,(N)(S)靠近一步。

    (1 leq n,m leq 1000)

    题解

    先判断不存在解的情况。如果((i,j))位置是白色,且这个位置放(S),那么第(i)行和第(j)列不能存在黑色位置,因为既然能达到黑色位置,则经过有限次操作后,必定能到达((i,j)),而((i,j))是不可达的。如果((i,j))位置是黑色,且这个位置放(S),那么第(i)行和第(j)列只能存在一段连续的黑色位置,因为若存在两端或者更多段黑色位置,则段与段之间白色的部分必定可达。检查完所有的位置后,如果某行或者某列所有的位置都不能放(S),则解不存在。

    经过上面的检查后,棋盘中黑色的位置组成了一个个连通块,在每个连通块的边界都放上(S),显然,一个连通块只需要在块内任意位置处放入一个(N)就行了。故最少的(N)的个数就是连通块的个数。

    1343D - Constant Palindrome Sum

    给一个长度为(n)的序列(A),问最少需要几次操作使得(forall i in [1;frac{n}{2}]),有(a_i + a_{n-i+1} = X)

    一次操作:将任意一个数置为区间([1;k])内的数。

    (1 leq a_i leq k leq 2e5)(1 leq n leq 2e5),且(n)为偶数。

    题解

    (x = min(a_i, a_{n - i + 1}))(y = max(a_i, a_{n - i + 1}))。如果(X)落在区间:

    • ([2, x]),第(i)对的贡献为2
    • ([x + 1, x + y - 1]),第(i)对的贡献为1
    • ([x+y, x+y]),第(i)对的贡献为0
    • ([x + y + 1, k + y]),第(i)对的贡献为1
    • ([k + y + 1, 2 * k]),第(i)对的贡献为2

    显然,我们可以在每一对 (i) 所对应的这些区间上预先加上贡献,最后求区间([2; 2*k])上的最小值就是最少操作次数。区间操作,单点查询,可以用树状数组。但还有比较简单的方法,利用差分:在区间([l,r])上加1,则(b[l] += 1)(b[r + 1] -= 1),处理完所有的区间后,扫描一遍求前缀和,既(b[i] += b[i - 1]),最后(answer = min{b_i})

    1342C - Yet Another Counting Problem

    给两个正整数(a,b),问在区间([L,R])内有多少个数满足:((x \% a) \% b ~~!= ~~(x\%b)\%a)

    (1 leq a, b, L, R leq 1e18)

    题解

    不妨假设(a leq b),如果((x \% a) \% b ~~= ~~(x\%b)\%a),有:(x \% a ~~= ~~(x\%b)\%a),并且(a | (x - x \% b))。假设(x = p * b + r),则有(a |(p*b)),既(p)(frac{a}{gcd(a,b)})的倍数,既(p)的取值为:({0, frac{a}{gcd(a,b)}, frac{2a}{gcd(a,b)}, frac{3a}{gcd(a,b)},... }),而(r)的取值为:({0, 1, 2, 3, ...,b-1})。所以区间([0, R])内满足相等条件的(x)的个数为:(frac{(R+1)*gcd(a,b)}{ab} * b + min(b, (R+1)\%(frac{ab}{gcd(a,b)})))

    1342D - Multiple Testcases

    给一个长度为(n)的序列(A)(1 leq a_i leq k),和长度为(k)的序列(C)(c_1 geq c_2 geq c_3 geq ... geq c_k),问(A)最少能被分成几组,使得每组都满足如下条件:

    • 记每组中大于或者等于(i) 的个数为(g_i),有:(g_i leq c_i)

    (1 leq n,k le 2e5)

    题解

    记最少组数为(ans),有:(ans = maxlceil frac{g_i}{c_i} ceil)。怎么构造呢,令(a_i in ans[i \% ans])(i in {0,1,2,...,n-1})。还是比较巧妙得!

    1341D - Nastya and Scoreboard

    (n)个数字显示器,问再打开(k)个显示器中导管后,这(n)个数字显示器所组成的最大整数?

    (1 leq n, k leq 2000)

    题解

    (dp[i][j]:=) (i) 个数字显示器再打开(j)个导管时,第(i)个数字显示器显示的最大数字。为了满足最大的整数,第一个显示器显示的数字应该尽可能的大,实际上就是(dp[0][k])。从后向前递归,**记录所有合法的状态(dp[i][j]) **,再从前向后回溯就能找到所有合法的显示器的数字了。

    string s[10] = {"1110111", "0010010", "1011101", "1011011", "0111010", "1101011", "1101111", "1010010", "1111111", "1111011"};
    int get_int(string str) {
        int res = 0;
        for (int i = 6, j = 1; ~i; i--, j *= 2) if (str[i] == '1') res += j;
        return res; 
    }
    
    int main()
    {   
        memset(dp, -1, sizeof(dp));
        memset(mp, -1, sizeof(mp));
    
        cin >> n >> k;
    
        for (int i = 0; i < n; i++) {
            string t;
            cin >> t;
            int x = get_int(t);
            for (int j = 0; j < 10; j++) {
                int y = get_int(s[j]);
                if ((x & y) == x) mp[i][__builtin_popcount(x ^ y)] = j;
            }
        }
    
        for (int i = 0; i < 8; i++) dp[n - 1][i] = mp[n - 1][i];
    
        for (int i = n - 2; ~i; i--) {
            for (int j = 0; j <= k; j++) if (dp[i + 1][j] >= 0){
                for (int p = 0; p <= 7 && j + p <= k; p++) dp[i][j + p] = max(dp[i][j + p],  mp[i][p]);
            }
        }
    
        int cnt = 0;
        for (int i = 0; i < n; i++) {
            int u = dp[i][k - cnt];
            cout << u;
            if (u == -1) return 0;
            for (int j = 0; j <= 7; j++) if (mp[i][j] == u) {
                cnt += j;
                break;
            }
        }
        cout << endl;
    
        return 0;
    }
    
    

    1338B - Edge Weight Assignment(好题:通过构造点权值来构造边权值)

    给一颗树,为每条边赋一个权值(正整数),问最少和最多需要几个不同的正整数,使得任意一对叶子之间路径异或值为0,既有:(l_1w_0v_1w_1v_2w_2...v_iw_il_2)(w_0 igoplus w_1 igoplus w_2 igoplus ... igoplus w_i = 0)

    题解

    最少需要1个或者3个,也就是对所有的边赋值同一个整整数,分类讨论一下即可。

    为每个叶子节点赋点权值:0,为非叶节点赋点权值:(2^i)。则边权值为:(w(e(i,j)) = v_i igoplus v_j)。显然,任意一对叶子之间的路径异或为0,所以最多需要(e - sum_v(leaf(v) - 1))个正整数。简直妙级了!

    (leaf(v))表示节点(v)的叶儿子个数.

    1336A - Linova and Kingdom

    给一颗(n)个节点的树,根为1,从树中选取(k)个节点建立工厂,剩余的所有节点建立公园,问这(k)个工厂各自派出一个工人,这些工人走到树根最多能游玩几个公园?工人只能沿着最短路走。

    (1 leq k leq n leq 2e5)

    题解

    当一个节点被选择建立工厂时,它的所有子节点在之前就已经被选择建立工厂,否则具有更优的方案。所以每个节点的实际贡献为(dep[u] - size[u])。求出每个点的实际贡献,排个序,从大往小选择(k)个贡献较大的节点。

    1333C - Eugene and an array

    给一个序列,问有多少个子串满足:子串的任意一个子串都是好子串 ?

    • 好子串(A_{l...r})(a_l + a_{l +1} + a_{l + 2} + ... + a[r] eq 0)

    (1 leq n leq 2e5)(-10^9 leq a_i leq 10^9)

    题解

    (R[i])表示以(i)为左端点且最短 非好子串 的右端点位置,既(a_i + a_{i + 1} + a_{i + 2} + ... + a_{R[i]} = 0)。当然,也可能不存在(R[i])。记(L[R[i]] = i),那么(i)位置为左端点的好子串个数就是:(R[j] - i) 或者是 (n - i + 1)(j = (argmin_jR[j] geq i) && (L[R[j]] geq i))(j) 的取值应该使得(R[j])尽量靠近(i)的同时其左边界要大于等于(i)

    怎么求(R[i])?求出所有位置的前缀和(sum[i]),显然有(sum[R[i]] = sum[i-1]),用一个二维数组记录相同(sum)值出现的所有位置,然后二分查找满足等式且最小的(R[i])就可以了。

  • 相关阅读:
    浅谈Cauchy不等式
    终于结束的起点——CSP-S 2019 第二轮游记
    LOJ 10172 涂抹果酱
    数字表格
    CSP-S 2019 第一轮 游记
    20191011模拟赛
    Luogu 2327 扫雷
    NOIAC 30 candy
    FormData文件上传
    sde表空间无法导入数据和编辑
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/14952431.html
Copyright © 2020-2023  润新知