• 【洛谷】P4199 万径人踪灭


    题解

    每种字符跑一遍FFT,得到(i + j = k)时匹配的个数(要÷2,对于相同位置的最后再加上

    然后算出(2^{cnt[k]})的和,最后再减去用mancher匹配出的连续回文子串的个数即可

    代码

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define pdi pair<db,int>
    #define mp make_pair
    #define pb push_back
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define eps 1e-8
    #define mo 974711
    #define MAXN 100005
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 + c - '0';
    	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) {
    	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    const int MOD = 998244353,MAXL = (1 << 20);
    const int M = 1000000007;
    
    int pw[400005],f[400005],N,W[MAXL + 5],ans,r[400005],mx,pos,cnt[400005];
    char s[400005];
    char t[400005];
    int fpow(int x,int c) {
        int res = 1,t = x;
        while(c) {
    	if(c & 1) res = 1LL * res * t % MOD;
    	t = 1LL * t * t % MOD;
    	c >>= 1;
        }
        return res;
    }
    void NTT(int *p,int L,int on) {
        for(int i = 1 , j = L >> 1 ; i < L - 1 ; ++i) {
    	if(i < j) swap(p[i],p[j]);
    	int k = L >> 1;
    	while(j >= k) {
    	    j -= k;
    	    k >>= 1;
    	}
    	j += k;
        }
        for(int h = 2 ; h <= L ; h <<= 1) {
    	int wn = W[(MAXL + MAXL * on / h) % MAXL];
    	for(int k = 0 ; k < L ; k += h) {
    	    int w = 1;
    	    for(int j = k ; j < k + h / 2 ; ++j) {
    		int u = p[j],t = 1LL * w * p[j + h / 2] % MOD;
    		p[j] = u + t >= MOD ? u + t - MOD : u + t;
    		p[j + h / 2] = u - t >= 0 ? u - t : u - t + MOD;
    		w = 1LL * w * wn % MOD;
    	    }
    	}
        }
        if(on == -1) {
    	int InvL = fpow(L,MOD - 2);
    	for(int i = 0 ; i < L ; ++i) p[i] = 1LL * InvL * p[i] % MOD;
        }
    }
    void Init() {
        W[0] = 1;
        W[1] = fpow(3,(MOD - 1) / MAXL);
        for(int i = 2; i < MAXL ; ++i) W[i] = 1LL * W[i - 1] * W[1] % MOD;
        pw[0] = 1;
        for(int i = 1 ; i <= 400000 ; ++i) pw[i] = 1LL * pw[i - 1] * 2 % M;
    }
    void Solve() {
        scanf("%s",s + 1);
        N = strlen(s + 1);
        for(int i = 1 ; i <= N ; ++i) {
    	if(s[i] == 'a') f[i] = 1;
        }
        int len = 1;
        while(len <= 2 * N) {len <<= 1;}
        NTT(f,len,1);
        for(int i = 0 ; i < len ; ++i) f[i] = 1LL * f[i] * f[i] % MOD;
        NTT(f,len,-1);
        for(int i = 0 ; i < len ; ++i) {
    	cnt[i] += f[i] / 2;
        }
        memset(f,0,sizeof(f));
        for(int i = 1 ; i <= N ; ++i) {
    	if(s[i] == 'b') f[i] = 1;
        }
        NTT(f,len,1);
        for(int i = 0 ; i < len ; ++i) f[i] = 1LL * f[i] * f[i] % MOD;
        NTT(f,len,-1);
        for(int i = 0 ; i < len ; ++i) {
    	cnt[i] += f[i] / 2;
        }
        for(int i = 0 ; i < len ; ++i) {
    	if(i % 2 == 0 && i / 2 >= 1 && i / 2 <= N) ++cnt[i];
    	ans = ans + pw[cnt[i]] - 1 >= M ? ans + pw[cnt[i]] - 1 - M : ans + pw[cnt[i]] - 1;
        }
        int p = 1;
        t[++p] = '$';
        for(int i = 1 ; i <= N ; ++i) {
    	t[++p] = s[i];
    	t[++p] = '$';
        }
        mx = 1,pos = 1,r[1] = 1;
        for(int i = 2 ; i <= p ; ++i) {
    	if(mx >= i) r[i] = min(r[2 * pos - i],mx - i + 1);
    	else r[i] = 1;
    	while(i + r[i] <= p && i - r[i] >= 1 && t[i + r[i]] == t[i - r[i]]) ++r[i];
    	if(i + r[i] - 1 > mx) {
    	    mx = i + r[i] - 1;
    	    pos = i;
    	}
        }
        for(int i = 1 ; i <= p ; ++i) {
    	r[i] /= 2;
    	ans = ans - r[i] >= 0 ? ans - r[i] : ans - r[i] + M;
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
        return 0;
    }
    
  • 相关阅读:
    剑指offer--38.左旋转字符串
    剑指offer--37.和为S的两个数字
    剑指offer--35.数组中只出现一次的数字
    剑指offer--34.数字在排序数组中出现的次数
    剑指offer--33.丑数
    剑指offer--36.整数中1出现的次数(从1到n整数中1出现的次数)
    剑指offer--32.把数组排成最小的数
    剑指offer--31.二叉树中和为某一值的路径
    剑指offer--30.二叉搜索树的后序遍历序列
    剑指offer--29.从上往下打印二叉树
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10096179.html
Copyright © 2020-2023  润新知