I-string_2019牛オフサマースクール、より合宿(その4)

問題の意味

!= Bと!= revは(b)の文字列をbと等しくないと文字列である場合、改訂(b)はBで表される文字列を再生し、例えばREV(ABCD)= DCBAは、
文字列がすべてではない判定された文字列を与えられましたサブストリングの数が等しいです

問題の解決策

これは、サブストリングの数に等しくない部分文字列の数を減算し、次に、接尾辞配列S#1 REV(sで)サブストリングの数を用いて決定「#」を含む文字「#」が含まれている((LEN(複数可\ )+ 1)^ 2 \) エミュレートされた文字の#のための特定および#への出発点とで構成される右端の文字列の左側には、明らかにすべてのサブストリングの#を含むように取り出し、そしてこれらの部分文字列が等しくないことができます。
したがって、結果を追求することである\(ANS = \ FRAC {( 2len(S)+1)*は(2len(S))} {2} - \ sum_ {i = 2} ^ {2len(S)+1}高さ[ I] - (LEN(S)+ +1)^ 2 \) 結果は見つける、例えばS = ABACとして、(b)の結果= REVを求めて含むように({A、B、Cを\ 、 AB&、BA、AC、CA、CAB、ABA、BAC、ABAC、CABA} \)に加えて見ることができる({A、B、C \ \、ABAを}) いくつかの回文配列、及び残りの文字列でありますペアで、その後、私たちは一緒に木が異なる性質の回文回文文字列の番号の前にANSを見つけて2で割った答えです

コード

#include <bits/stdc++.h>

const int mx = 5e5+5;
typedef long long ll;
char str[mx];

int t1[mx], t2[mx], c[mx];
int sa[mx], rank[mx], height[mx];

bool cmp(int *r, int a, int b, int l) {
    return r[a] == r[b] && r[a+l] == r[b+l];
}

void da(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];

        std::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;
    }
}

const int N = 26;
struct pTree {
    int Next[mx][N];
    int fail[mx];
    ll cnt[mx];
    ll sum[mx];
    int num[mx];
    int len[mx];
    int S[mx];
    int last, n, p, cur, now;

    int newnode(int l) {
        for (int i = 0; i < N; i++) Next[p][i] = 0;
        cnt[p] = num[p] = 0;
        len[p] = l;
        return p++;
    }

    void init() {
        n = p = 0;
        newnode(0);
        newnode(-1);
        last = 0;
        S[n] = -1;
        fail[0] = 1;
    }

    int getFail(int x) {
        while (S[n - len[x] - 1] != S[n]) x = fail[x];
        return x;
    }

    bool add(int c) {
        S[++n] = c;
        cur = getFail(last);
        bool flag = false;
        if (!Next[cur][c]) {
            flag = true;
            now = newnode(len[cur] + 2);
            fail[now] = Next[getFail(fail[cur])][c];
            Next[cur][c] = now;
            num[now] = num[fail[now]] + 1;
        }
        last = Next[cur][c];
        cnt[last]++;
        return flag;
    }
    void count() {
        for (int i = p-1; i >= 0; i--) cnt[fail[i]] += cnt[i];
    }
}tree;

int main() {
    scanf("%s", str);
    int len = std::strlen(str);
    str[len] = '#';
    for (int i = len+1; i <= 2*len; i++) str[i] = str[2*len-i];
    str[2*len+1] = '\0';

    int n = 2*len+1;
    da(n, 128);
    ll tot = 1LL * (2*len+1) * (2*len+2)/2;
    tot -= 1LL * (len+1) * (len+1);
    for (int i = 2; i <= n; i++) tot -= height[i];

    tree.init();
    for (int i = 0; i < len; i++) tree.add(str[i]-'a');
    printf("%lld\n", (tot+tree.p-2)/2);
    return 0;
}

おすすめ

転載: www.cnblogs.com/bpdwn-cnblogs/p/11290646.html