CF1320路Div1 D.Reachableストリングス题解

効果の対象に

長さが与えられた\(N- \) 01文字列\(S \) あなたは文字列操作を行うことができ、それぞれ3つの連続した位置:\(011 \ RIGHTARROW 110 \) \(110 \ RIGHTARROW 011 \)操作。

そこ\(Q \)回のクエリ、クエリが別の文字列に1つの文字列から変更するかどうか尋ね、同じ長さの2つずつのサブ文字列を与えられました。

問題の解決策

まず、操作が変化しないことがわかった\(1 \)番号を。プレフィックスと最初によって決定することができる(1 \)\数が等しいです。

文字列は、隣接する二つの表示されない場合は、\(1 \)を、そう簡単にあなたが任意の有効なアクションを行うことができないことを取得するには、直接等しいかどうかを判断します。このステップでは、ハッシュまたはSA SAMまたは達成することができます。

そうでなければ、我々はまた、奇数ビット(サブある奇数ビット)で新しい不変、見つかった\(1 \)番号と偶数ビットを(1 \)\数は変更されません!したがって、我々は、プレフィックスを計算し、奇数のビットは二つの文字列決定される\(1 \) そして同じか否かを判断します

提出します

良い成績を得るためのWA5!

これはレッスンが正しく、十分条件ではないことができ不変量を使用するのは簡単です私たちを提供します。

私たちは、素晴らしいアイデアを必要としています。

\(0 \)悪役として、\(1 \)オープンスペースとして。各操作は、悪役の間の相対的な位置を変更することなく、悪役の長さに2つの移動ユニットとして理解することができます。

したがって、右悪役パリティ位置にそれぞれ左は一定です。

提供されるクエリ文字列\([L_1、R_1]、[L_2、R_2] \)は、最初の2つの部分文字列を判断する\(0 \)の数は等しいです。それらが等しい場合、それらはと呼ばれる\(K \) 左から右への第一列に配置され\(I \)を\(0 \)があるSの位置である(a_iを\)\、2番目の文字列である(B_i \)\

必要十分条件は、任意のための\(I \)、\ (a_iを- L_1 \当量b_i - L_2(\ MOD 2)\)

(条件の妥当性、本当に良いカードについては、と書いていません)

我々各S \(0 \)場合には、全て一緒に\(0 \)添字がこの位置に奇数、フィルである\(1 \) そうでなければ充填(\ 0)\、覚え新しい文字列がある\(T_1 \)この新しい文字列(01 \)は\互換性があり、フォーム\(T_2 \)

するには、\(T = T_1T_2 \)接尾辞配列またはサフィックスオートマトンを構築します。常に問題になる尋ねる\(T \)二つのサブ文字列では同じです。

これは古典的な問題です。

#include <bits/stdc++.h>
#define debug(x) cerr << #x << " " << (x) << endl
using namespace std;
 
const int N = 200005, K = 25;
 
int n, q, len[N << 2], par[N << 2], last = 0, cnt = 0;
char str[N];
map<char, int> ch[N << 2];
void extend (char c) {
    int p = last, np = ++cnt;
    len[np] = len[p] + 1;
    for (; ~p && !ch[p][c]; p = par[p]) ch[p][c] = np;
    if (p < 0) par[np] = 0;
    else {
        int q = ch[p][c];
        if (len[q] == len[p] + 1) par[np] = q;
        else {
            int nq = ++cnt;
            ch[nq] = ch[q], len[nq] = len[p] + 1;
            par[nq] = par[q], par[q] = par[np] = nq;
            for (; ~p && ch[p][c] == q; p = par[p]) ch[p][c] = nq;
        }
    }
    last = np;
}
 
int tot = 0, id[N << 1], fa[N << 2][K], Log2[N << 2];
int zero[N << 1], pos[N];
 
int find_pos (int l, int r) {
    int u = id[r];
    for (int i = Log2[cnt]; i >= 0; i--) {
        if (~fa[u][i] && len[fa[u][i]] > r - l) u = fa[u][i];
    }
    return u;
}
 
int main () {
    scanf("%d%s", &n, &str);
    par[0] = -1, len[0] = 0;
    for (int i = 0; i < n; i++) {
        if (str[i] == '0') {
            pos[tot] = i;
            zero[tot++] = i & 1;
        }
    }
    
 
    for (int i = 0, j = 0; i < n; i++) {
        if (str[i] == '0') {
            zero[tot + j] = i & 1 ^ 1;
            j++;
        }
    }
 
    for (int i = 0; i < (tot << 1); i++) extend(zero[i] + '0'), id[i] = last;
 
    Log2[1] = 0;
    for (int i = 2; i <= cnt; i++) Log2[i] = Log2[i >> 1] + 1;
    for (int i = 0; i <= cnt; i++) fa[i][0] = par[i];
    for (int i = 1; i <= Log2[cnt]; i++) {
        for (int j = 0; j <= cnt; j++) {
            if (fa[j][i - 1] < 0) fa[j][i] = -1;
            else fa[j][i] = fa[fa[j][i - 1]][i - 1];
        }
    }
 
    scanf("%d", &q);
    for (int i = 0; i < q; i++) {
        int l1, l2, len;
        scanf("%d%d%d", &l1, &l2, &len), l1--, l2--;
 
        int L1 = lower_bound(pos, pos + tot, l1) - pos, R1 = lower_bound(pos, pos + tot, l1 + len) - pos;
        int L2 = lower_bound(pos, pos + tot, l2) - pos, R2 = lower_bound(pos, pos + tot, l2 + len) - pos;
 
        bool flag = true;
        if (R1 - L1 != R2 - L2) flag = false;
        if (l1 & 1) L1 += tot, R1 += tot;
        if (l2 & 1) L2 += tot, R2 += tot;
        if (L1 < R1 && L2 < R2 && find_pos(L1, R1 - 1) != find_pos(L2, R2 - 1)) flag = false;
        if (flag) puts("Yes");
        else puts("No");
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/mathematician/p/12516909.html