CF 1320D Reachable Strings 后缀数组

确定性解法:后缀数组

众所周知 hash 由于不能完全避免冲突常常会被 cf hacker 卡掉,此题有更稳定的解法

考虑将原串进行简化,由于只有连续的 1 会造成不确定的匹配,可以只对 0 建立一个新串

对于一段连续的 1,后面的 0 建立新字符,如果有奇数个 1 就建立 1,偶数个就建立 0

例如: 1110 -> 1,110 -> 0,11011 -> 0

由于最后的 1 是没有后导 0 的就不计入新串

然后新串的 lcp 就可以对应到原串的对应位置,新串 lcp 匹配就等价于原串可达

比如 011010 和 110010 转换后都会变为 001

然后考虑左右两端不是 0 的情况

就类似分块,将左右边界用 1 的数量特判即可,特判的情况很多注意细节

  • 区间全是 1
  • 区间只有一个 0 (边界特判完后没有 0)
#include <bits/stdc++.h>

#define ll long long
#define X first
#define Y second
#define sz size()
#define all(x) x.begin(), x.end()
using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<long long> vl;

template<class T>
inline bool scan(T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return 0; //EOF
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}

const ll mod = 1e9 + 7;
const int maxn = 2e5 + 50;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;

ll qp(ll x, ll n) {
    ll res = 1;
    x %= mod;
    while (n > 0) {
        if (n & 1) res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}

char t[maxn], s[maxn];

namespace SA {
    const int maxn = 2e5 + 10;
    int t1[maxn], t2[maxn], c[maxn];
    int Rank[maxn], height[maxn];
    int RMQ[maxn];
    int mm[maxn];
    int sa[maxn];
    int best[25][maxn];
    bool cmp(int *r, int a, int b, int l) {
        return r[a] == r[b] && r[a + l] == r[b + l];
    }
    void da(char str[], int sa[], int Rank[], int height[], int n, int m) {
        n++;
        int i, j, p, *x = t1, *y = t2;
        for (i = 0; i < m; i++)c[i] = 0;
        for (i = 0; i < n; i++)c[x[i] = str[i]]++;
        for (i = 1; i < m; i++)c[i] += c[i - 1];
        for (i = n - 1; i >= 0; i--)sa[--c[x[i]]] = i;
        for (j = 1; j <= n; j <<= 1) {
            p = 0;
            for (i = n - j; i < n; i++)y[p++] = i;
            for (i = 0; i < n; i++)if (sa[i] >= j)y[p++] = sa[i] - j;
            for (i = 0; i < m; i++)c[i] = 0;
            for (i = 0; i < n; i++)c[x[y[i]]]++;
            for (i = 1; i < m; i++)c[i] += c[i - 1];
            for (i = n - 1; i >= 0; i--)sa[--c[x[y[i]]]] = y[i];
            swap(x, y);
            p = 1;
            x[sa[0]] = 0;
            for (i = 1; i < n; i++)
                x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
            if (p >= n)break;
            m = p;
        }
        int k = 0;
        n--;
        for (i = 0; i <= n; i++)Rank[sa[i]] = i;
        for (i = 0; i < n; i++) {
            if (k)k--;
            j = sa[Rank[i] - 1];
            while (str[i + k] == str[j + k])k++;
            height[Rank[i]] = k;
        }
    }
    void initRMQ(int n) {
        for (int i = 1; i <= n; i++)
            RMQ[i] = height[i];
        mm[0] = -1;
        for (int i = 1; i <= n; i++)
            mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1];
        for (int i = 1; i <= n; i++)best[0][i] = i;
        for (int i = 1; i <= mm[n]; i++)
            for (int j = 1; j + (1 << i) - 1 <= n; j++) {
                int a = best[i - 1][j];
                int b = best[i - 1][j + (1 << (i - 1))];
                if (RMQ[a] < RMQ[b])best[i][j] = a;
                else best[i][j] = b;
            }
    }
    int askRMQ(int a, int b) {
        int t;
        t = mm[b - a + 1];
        b -= (1 << t) - 1;
        a = best[t][a];
        b = best[t][b];
        return RMQ[a] < RMQ[b] ? a : b;
    }
    int lcp(int a, int b) {
        a = Rank[a];
        b = Rank[b];
        if (a > b) swap(a, b);
        //cout << askRMQ(a + 1, b) << endl;
        return height[askRMQ(a + 1, b)];
    }
    void preprocess(char *str, int n, int m) {
        da(str, sa, Rank, height, n, m);
        initRMQ(n);
    }
}

int n, q;
int sum[maxn], L[maxn], R[maxn], id[maxn];

int main(int argc, char *argv[]) {
    scanf("%d%s%d", &n, t + 1, &q);
    int pre = -1;
    for (int i = 1; i <= n; ++i) {
        sum[i] = sum[i - 1] + (t[i] == '0');
        if (t[i] == '0') pre = i;
        L[i] = pre;
    }
    pre = -1;
    for (int i = n; i >= 1; --i) {
        if (t[i] == '0') pre = i;
        R[i] = pre;
    }
    int tot = 0;
    pre = 0;
    for (int i = 1; i <= n; ++i) {
        if (t[i] == '0') {
            s[id[i] = tot++] = (pre & 1) + '0';
            pre = 0;
        } else pre++;
    }
    SA::preprocess(s, tot, 130);
    for (int i = 1; i <= q; ++i) {
        int l1, l2, len;
        scanf("%d%d%d", &l1, &l2, &len);
        int r1 = l1 + len - 1;
        int r2 = l2 + len - 1;
        /*putchar(' ');
        for (int j = l1; j <= r1; ++j) putchar(s[j]);
        putchar(' ');
        for (int j = l2; j <= r2; ++j) putchar(s[j]);
        putchar(' ');*/
        int z1 = sum[r1] - sum[l1 - 1];
        int z2 = sum[r2] - sum[l2 - 1];
        if (z1 != z2) {
            puts("NO");
            continue;
        }
        if (z1 == 0) {
            puts("YES");
            continue;
        }
        int front1 = R[l1] - l1, front2 = R[l2] - l2, last1 = r1 - L[r1], last2 = r2 - L[r2];
        if (front1 % 2 != front2 % 2 || last1 % 2 != last2 % 2) {
            puts("NO");
            continue;
        }
        if (z1 == 1) {
            puts("YES");
            continue;
        }
        if (id[R[l1]] == id[R[l2]]) {
            puts("YES");
            continue;
        }
        int alen = SA::lcp(id[R[l1]] + 1, id[R[l2]] + 1);
        if (alen >= z1 - 1) {
            puts("YES");
        } else puts("NO");
    }
    return 0;
}
posted @ 2020-03-06 18:17  badcw  阅读(260)  评论(0编辑  收藏  举报