[Codeforces Gym - 101617C] Flipping Out

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013578420/article/details/82532619

题目链接

https://vjudge.net/contest/248767#problem/C

题目大意

给你n个仅含’T’, ‘H’的串, 前n-1个串为已知的模式串, 第n个串为生成串, 生成串是根据n个模式串生成出来的。 对于生成串的第i位表示, 前缀i-1一共出现了偶数次模式串则为’T’, 奇数次则为’H’。 求缺失的模式串的方案数, 无穷则输出-1, 不能和已有的模式串重复。 ( 10 6 , )

题目思路

首先建立AC自动机, 将已有串的贡献消去, 剩下确实串对答案的影响, 即对于前缀i, 缺失串出现次数的奇偶性。
做差分数组, 表示缺失串是否为原串的前缀i的一个后缀
做翻转, 表示缺失串是否为原串的后缀i的一个前缀
如果所有元素都是0, 有无穷种。
否则仍取一个1, 对于其他的后缀, 求出lcp, 如果这个后缀对应元素为0, 则用lcp更新下界, 如果对应元素为1, 则更新上界。
最后将所有的可能用hash与已知模式串去重, 输出最后的方案数。

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>

#define ll long long
#define ull unsigned ll 

using namespace std;

const int N = (int)1e6 + 10;

int n; char str[N]; int st[N], ed[N];
int rt, cnt, ch[N][2], fa[N], fail[N], g[N], pre[N];

int NewNd(){
    cnt ++;
    ch[cnt][0] = ch[cnt][1] = 0;
    fa[cnt] = fail[cnt] = g[cnt] = pre[cnt] = 0;
    return cnt;
}

int head, tail, que[N];
void make_fail(){
    head = tail = 0;
    que[tail = 1] = rt;
    while (head < tail){
        int u = que[++ head];
        for (int j = 0; j < 2; j ++)
            if (ch[u][j]) que[++ tail] = ch[u][j];
        int p = fa[u];
        while (u != rt && p != rt && !ch[fail[p]][pre[u]]) p = fail[p];
        if (p == rt) continue;
        fail[u] = ch[fail[p]][pre[u]];
        g[u] += g[fail[u]];
    }
}

int a[N], b[N], len; ull pw[N], ps[N];
ull get(int l, int r){
    return ps[r] - ps[l - 1] * pw[r - l + 1];
}
int lcp(int x, int y){
    int L = 1, R = min(len - y + 1, len - x + 1), ret = 0;
    while (L <= R){
        int mid = (L + R) / 2;
        if (get(x, x + mid - 1) == get(y, y + mid - 1)) ret = mid, L = mid + 1;
        else R = mid - 1;
    }
    return ret;
}

int main()
{
    pw[0] = 1;
    for (int i = 1; i < N; i ++) pw[i] = pw[i - 1] * 233;

    while (scanf("%d", &n) != EOF){
        ed[0] = 0;
        for (int i = 1; i <= n; i ++){
            st[i] = ed[i - 1] + 1;
            scanf("%s", str + st[i]);
            ed[i] = strlen(str + st[i]) + st[i] - 1;
        }
        for (int i = 1; i <= ed[n]; i ++)
            str[i] = str[i] == 'T' ? '0' : '1';

        cnt = 0; ch[0][0] = ch[0][1] = 0;
        for (int i = 1; i < n; i ++){
            int p = rt;
            for (int j = st[i]; j <= ed[i]; j ++){
                int nxt = str[j] - '0';
                if (ch[p][nxt] == 0){
                    int Nd = NewNd();
                    ch[p][nxt] = Nd, fa[Nd] = p, pre[Nd] = nxt;
                }
                p = ch[p][nxt];
            }
            g[p] ++;
        }

        make_fail();

        int sum = 0;
        for (int j = st[n], u = rt; j < ed[n]; j ++){
            int nxt = str[j] - '0';
            while (u != rt && !ch[u][nxt]) u = fail[u];
            if (!ch[u][nxt]) ;
            else {u = ch[u][nxt]; sum += g[u];}

            b[j - st[n] + 1] = abs(str[j + 1] - '0' - (sum & 1));
            a[j - st[n] + 1] = nxt;
        }

        if (str[st[n]] != '0'){puts("0"); continue;}

        len = ed[n] - st[n];
        for (int j = len; j >= 1; j --) b[j] = abs(b[j] - b[j - 1]); 

        bool infi = 1;
        for (int j = 1; j <= len && infi; j ++)
            if (b[j] != 0) infi = 0;

        if (infi) {puts("-1"); continue;}

        reverse(a + 1, a + len + 1);
        reverse(b + 1, b + len + 1);

        int x = 0, ans = 0;
        for (int i = 1; i <= len && !x; i ++)
            if (b[i]) x = i;

        map<ull, bool > M;
        for (int i = 1; i < n; i ++){
            ull tmp = 0;
            for (int j = ed[i]; j >= st[i]; j --)
                tmp = tmp * 233 + str[j] - '0' + 1;
            M[tmp] = 1;
        }

        for (int i = 1; i <= len; i ++) ps[i] = ps[i - 1] * 233 + a[i] + 1;

        int L = 1, R = len - x + 1;
        for (int i = 1; i <= len; i ++){
            if (i == x) continue;
            int res = lcp(i, x);
            if (b[i] == 0) L = max(L, res + 1);
            else R = min(R, res);
        }


        for (int i = L; i <= R; i ++){
            ull ret = get(x, x + i - 1);
            if (!M[ret]) ans ++;
        }

        printf("%d\n", ans);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013578420/article/details/82532619