• CF1043G Speckled Band


    CF1043G Speckled Band

    CF1043G Speckled Band - 洛谷

    (Description)

    给定字符串 (S),每次询问 ((l, r)),将子串 ([l, r]) 划分为若干段使得至少有两段相同,求拆分后 本质不同的段 的最小个数。

    (Solution)

    结果为(-1) 当且仅当子串中每个字符只出现一次,否则可以发现 (ans = 1/2/3/4)

    (len = r - l + 1),以下 (A, B) 表示字符串。

    1. (ans = 1),此时子串为 (AAAA...),枚举 (len) 的约数 (c)([l. r]) 有长度为 (c) 的循环节的充要条件为 ([l, r - c] = [l + c, r])
    2. (ans = 2),子串为 (ABA / AAB / BAA),前者可以求出子串的最短 (border) 判断;对于后两者,考虑求出 (f_i, g_i) 表示以 (i) 为 开头/结尾 的最短 (AA) 串长度,那么 (f_l leq len or g_r leq len)
    3. (ans = 3),子串为 (ABAC / BACA / BAAC),对于前二者,只需要判断 ([l, r]) 中是否有字符出现超过一次(以它们为 (A));后者只需要判断 (min_l^r l + f_l leq r)
    4. 否则 (ans = 4)

    求最短 (border)

    • 首先枚举长度为 (1 ext{~} sqrt n)(border),否则最短 (border)([l, r]) 的后缀排名不超过 (sqrt n)
    • 考虑反证法,若 (|border| > sqrt n) 且与 ([l, r]) 的后缀排名超过 (sqrt n),则可以证明有更短的 (border),与要求矛盾。

    (f_i)

    • 方法与 NOI2016 优秀的拆分 类似。
    • 考虑求长度为 (2L)(AA) 串,将原串每 (L) 位设置关键点,则长为 (2L)(AA) 串一定经过且只经过两个关键点。
    • 可以以关键点将 (A) 分为 (LCP)(LCS)
    • 求出相邻关键点的 (lcp)(lcs) ,那么形成 (AA) 串的充要条件为 (lcp + lcs > L),开头区间为 ([l - lcp + 1, l - len + lcs])
    • (g) 类似。

    (Code)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define N 200000
    #define L 18
    
    #define fo(i, x, y) for(int i = x, end_##i = y; i <= end_##i; i ++)
    #define fd(i, x, y) for(int i = x, end_##i = y; i >= end_##i; i --)
    #define mcp(a, b) memcpy(a, b, sizeof b)
    #define Mes(a, x) memset(a, x, sizeof a)
    
    void read(int &x) {
        char ch = getchar(); x = 0;
        while (ch < '0' || ch > '9') ch = getchar();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
    }
    
    char ch[N + 1];
    int n;
    
    struct HASH {
        int h[N + 1], mi[N + 1], inv[N + 1], p, mo;
        int pw(int x, int k) {
            int res = 1;
            while (k) {
                if (k & 1) res = 1ll * res * x % mo;
                x = 1ll * x * x % mo;
                k >>= 1;
            }
            return res;
        }
        void build(int x, int y) {
            mo = x, p = y;
            mi[0] = 1;
            fo(i, 1, n) mi[i] = 1ll * mi[i - 1] * p % mo;
            inv[n] = pw(mi[n], mo - 2);
            fd(i, n, 1)
                inv[i - 1] = 1ll * inv[i] * p % mo;
            fo(i, 1, n)
                h[i] = (h[i - 1] + 1ll * (ch[i] - 'a' + 1) * mi[i] % mo) % mo;
        }
        int hash(int l, int r) {
            return 1ll * (h[r] - h[l - 1] + mo) % mo * inv[l] % mo;
        }
    } h1, h2;
    
    bool check(int l, int r, int x, int y) {
        return h1.hash(l, r) == h1.hash(x, y) && h2.hash(l, r) == h2.hash(x, y);
    }
    
    int Log[N + 1];
    struct SA {
        int sa[N + 1], rk[N + 1], ht[N + 1], id[N + 1], oldrk[N << 1], buc[N + 1], px[N + 1], ft[N + 1][L + 1];
        int sk;
        void mysort() {
            fill(buc, buc + 1 + sk, 0);
            fo(i, 1, n) ++ buc[ px[i] = rk[id[i]] ];
            fo(i, 1, sk) buc[i] += buc[i - 1];
            fd(i, n, 1) sa[ buc[px[i]] -- ] = id[i];
        }
        bool pd(int x, int y, int z) { return oldrk[x] == oldrk[y] && oldrk[x + z] == oldrk[y + z]; }
        void build(char ch[]) {
            Mes(rk, 0), Mes(oldrk, 0);
            sk = 26;
            fo(i, 1, n) rk[ id[i] = i ] = ch[i] - 'a' + 1;
            mysort();
            for (int w = 1, p = 0; w <= n; w <<= 1, p = 0) {
                fo(i, n - w + 1, n) id[ ++ p ] = i;
                fo(i, 1, n) if (sa[i] > w)
                    id[ ++ p ] = sa[i] - w;
                mysort();
                mcp(oldrk, rk);
                sk = 0;
                fo(i, 1, n)
                    rk[sa[i]] = pd(sa[i], sa[i - 1], w) ? sk : ++ sk;
                if (sk == n) {
                    fo(i, 1, n) sa[rk[i]] = i;
                    break;
                }
            }
            sk = 0;
            fo(i, 1, n) {
                if (sk) -- sk;
                while (ch[i + sk] == ch[sa[rk[i] - 1] + sk])
                    ++ sk;
                ht[rk[i]] = sk;
            }
            fo(i, 1, n) ft[i][0] = ht[i];
            fo(j, 0, L - 1) fo(i, 1, n)
                ft[i][j + 1] = (i + (1 << j) <= n) ? min(ft[i][j], ft[i + (1 << j)][j]) : ft[i][j];
        }
        int dt;
        int get(int l, int r) {
            l = rk[l], r = rk[r];
            if (l > r) swap(l, r);
            if (++ l == r) return ft[l][0];
            dt = Log[r - l + 1];
            return min(ft[l][dt], ft[r - (1 << dt) + 1][dt]);
        }
    } s1, s2;
    
    struct Tree {
        #define ls (t << 1)
        #define rs (t << 1 | 1)
        int vl[N << 2];
        Tree() { Mes(vl, 0x3f); }
        void Add(int t, int l, int r, int x, int y, int k, int lz) {
            if (lz < vl[t]) vl[t] = lz;
            if (x <= l && r <= y) {
                vl[t] = k; return;
            }
            int mid = l + r >> 1;
            if (x <= mid) Add(ls, l, mid, x, y, k, vl[t]);
            if (y > mid) Add(rs, mid + 1, r, x, y, k, vl[t]);
        }
        void fil(int t, int l, int r, int lz, int at[]) {
            if (lz < vl[t]) vl[t] = lz;
            if (l == r) {
                at[l] = vl[t]; return;
            }
            int mid = l + r >> 1;
            fil(ls, l, mid, vl[t], at), fil(rs, mid + 1, r, vl[t], at);
        }
        #undef ls
        #undef rs
    } t1, t2;
    
    int gt[N + 1][L + 1], dl[N + 1], dr[N + 1], sc[N + 1][26];
    
    const int inf = 0x3f3f3f3f;
    int sqn;
    void Init() {
        Log[1] = 0;
        fo(i, 2, n) Log[i] = Log[i >> 1] + 1;
        h1.build(998244353, 37);
        h2.build(1000000007, 29);
        s1.build(ch);
        fd(i, (n >> 1), 1)
            swap(ch[i], ch[n - i + 1]);
        s2.build(ch);
        fd(i, (n >> 1), 1)
            swap(ch[i], ch[n - i + 1]);
        int l, r, lcp, lcs, dlen, pl, pr;
        fd(len, (n >> 1), 1) {
            fd(k, (n / len) - 1, 1) {
                l = len * k, r = len * (k + 1);
                lcs = s1.get(l, r);
                lcp = s2.get(n - l + 1, n - r + 1);
                if (lcp + lcs > len) {
                    lcp = min(lcp, len), lcs = min(lcs, len);
                    dlen = lcp + lcs - len - 1;
                    t1.Add(1, 1, n, l - lcp + 1, l - lcp + 1 + dlen, (len << 1), inf);
                    t2.Add(1, 1, n, r + lcs - 1 - dlen, r + lcs - 1, (len << 1), inf);
                }
            }
        }
        t1.fil(1, 1, n, inf, dl), t2.fil(1, 1, n, inf, dr);
        fo(i, 1, n) {
            fo(j, 0, 25) sc[i][j] = sc[i - 1][j];
            ++ sc[i][ch[i] - 'a'];
        }
        fo(i, 1, n) gt[i][0] = i + dl[i] - 1;
        fo(j, 0, L - 1) fo(i, 1, n)
            gt[i][j + 1] = (i + (1 << j) <= n) ? min(gt[i][j], gt[i + (1 << j)][j]) : gt[i][j];
        sqn = sqrt(n);
    }
    
    bool pd0(int l, int r) {
        fo(i, 0, 25) if (sc[r][i] - sc[l - 1][i] > 1)
            return 0;
        return 1;
    }
    
    int len, sq;
    bool pd1(int l, int r) {
        len = r - l + 1, sq = sqrt(len);
        if (check(l, r - 1, l + 1, r)) return 1;
        fo(i, 2, sq) if (len % i == 0)
            if (check(l, r - i, l + i, r) || check(l, r - len / i, l + len / i, r))
                return 1;
        return 0;
    }
    
    int min_ht;
    bool pd2(int l, int r) {
        len = r - l + 1;
        if (dl[l] <= len || dr[r] <= len)
            return 1;
        fd(i, min(sqn, (len >> 1)), 1) if (check(l, l + i - 1, r - i + 1, r))
            return 1;
        if (sqn >= (len >> 1)) return 0;
        min_ht = s1.ht[s1.rk[l]];
        fd(i, s1.rk[l] - 1, s1.rk[l] - sqn + 1) {
            if (i < 1) break;
            if ((l + r >> 1) < s1.sa[i] && s1.sa[i] <= r && s1.sa[i] + min_ht > r)
                return 1;
            min_ht = min(min_ht, s1.ht[i]);
        }
        min_ht = len;
        fo(i, s1.rk[l] + 1, s1.rk[l] + sqn - 1) {
            if (i > n) break;
            min_ht = min(min_ht, s1.ht[i]);
            if ((l + r >> 1) < s1.sa[i] && s1.sa[i] <= r && s1.sa[i] + min_ht > r)
                return 1;
        }
        return 0;
    }
    
    bool pd3(int l, int r) {
        return (sc[r][ch[l] - 'a'] - sc[l][ch[l] - 'a'] > 0) || (sc[r - 1][ch[r] - 'a'] - sc[l - 1][ch[r] - 'a'] > 0);
    }
    int dx; 
    int get_Min_dl(int l, int r) {
        if (l == r) return gt[l][0];
        dx = Log[r - l + 1];
        return min(gt[l][dx], gt[r - (1 << dx) + 1][dx]);
    }
    
    int main() {
        scanf("%d
    %s", &n, ch + 1);
        Init();
        int T, l, r; read(T);
        while (T --) {
            read(l), read(r);
            if (pd0(l, r))
                puts("-1");
            else
            if (pd1(l, r))
                puts("1");
            else
            if (pd2(l, r))
                puts("2");
            else
            if (pd3(l, r) || get_Min_dl(l, r) <= r)
                puts("3");
            else
                puts("4");
        }
        return 0;
    }
    
  • 相关阅读:
    oracle一些常用的单记录函数
    javascript闭包(closure)
    【Matlab开发】matlab中bar绘图设置与各种距离度量
    【Matlab开发】matlab中bar绘图设置与各种距离度量
    【Matlab开发】matlab中norm范数以及向量点积、绘图设置相关
    【Matlab开发】matlab中norm范数以及向量点积、绘图设置相关
    【编程开发】opencv实现对Mat中某一列或某一行的元素进行normalization
    【编程开发】opencv实现对Mat中某一列或某一行的元素进行normalization
    【编程开发】C语言中随机数rand使用注意事项
    【编程开发】C语言中随机数rand使用注意事项
  • 原文地址:https://www.cnblogs.com/zhouzj2004/p/14766252.html
Copyright © 2020-2023  润新知