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 \text{~} \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\n%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;
}
posted @ 2021-05-13 21:15  buzzhou  阅读(109)  评论(0编辑  收藏  举报