zoukankan      html  css  js  c++  java
  • 【洛谷】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;
    }
    
  • 相关阅读:
    高斯消元学习
    HDU 4596 Yet another end of the world(解一阶不定方程)
    Codeforces Round #318 div2
    HDU 4463 Outlets(一条边固定的最小生成树)
    HDU 4458 Shoot the Airplane(计算几何 判断点是否在n边形内)
    HDU 4112 Break the Chocolate(简单的数学推导)
    HDU 4111 Alice and Bob (博弈)
    POJ 2481 Cows(线段树单点更新)
    HDU 4288 Coder(STL水过)
    zoj 2563 Long Dominoes
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10096179.html
Copyright © 2011-2022 走看看