FFT例题

404 Not_Found

给定长度为 (n) 的置换 (p),判断字符串 (S) 的每个长度为 (n) 的子串再 (p) 下是否为不动点 (|S|, n le 1e5)

首先设置换是 (0, 1, 2, ..., n - 1) 那么置换后的序列 (t_{p_i} =s_i)
考虑使用 (hash) 是否能将两个式子卷起来,用一个点表示一个串的 (hash), (hash) 基数是 (b)

原串 (hash) :

[sum_{i = 0} ^ {n - 1} s_i b^i ]

(i) 开始 (n) 个字符的 (hash) 就是

[sum_{j = i} ^ {i + n - 1} s_j b^j ]

(i) 开始 (n) 个字符置换后的 (hash) 就是

[sum_{j = i} ^ {i + n - 1} s_j b ^ i b^{j - i} b^{t_{j - i} - (j - i)} ]

(c_i = b ^ {t_i - i}) 则式子变成

[sum_{j = i} ^ {i + n - 1} s_j b^j c_{j - i} ]

(s_j b^j) 带个 (x^j) 变成多项式 (s_j b^j x^j),让 (c_i) 带个 (x^{-i}) 变成 (c_i x ^ {-i}),这样两个式子卷起来,(x^i) 的系数就是长度为 (n) 的字符串变换后的 (hash) 值,和原串比较就好了

再说说怎么处理 (c_i x^{-i}),给它乘个 (x^{n - 1}) 相当于把 (c) 序列 (reverse) 后每一项变成 (c_i x ^ i)
乘完之后再除回来就行了

如果你觉着不太可能的化这是测试的代码

#include <bits/stdc++.h>
using namespace std;
#define rg register
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define gc getchar
inline int read(){
    rg char ch = gc();
    rg int x = 0, f = 0;
    while(!isdigit(ch)) f |= (ch == '-'), ch = gc();
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
    return f ? -x : x;
}
const int N = 1e5 + 5, mod = 998244353;
inline void Mod(int &x){
    x += (x >> 31) & mod;
}
int a[N], b[N], c[N];
inline void mul(int *a, int *b, int an, int bn, int *c){
//    memset(c, 0, (an + 1) * sizeof(int));
    rep(i, 0, an)
        rep(j, 0, i)
            Mod(c[i - j] += 1ll * a[i] * b[j] - mod);
}
inline int ksm(int a, int b){
    int ans = 1;
    while(b){
        if(b & 1) ans = 1ll * a * ans % mod;
        b >>= 1;
        a = 1ll * a * a % mod;
    }
    return ans;
}
const int G = 3, Gn = ksm(G, mod - 2);
int to[N];
inline void NTT(int *a, int lim, int flag){
    for(int i = 0; i < lim; ++i) if(to[i] > i) swap(a[i], a[to[i]]);
    for(int l = 2; l <= lim; l <<= 1){
        const int m = l >> 1, Gi = ksm(flag == 1 ? G : Gn, (mod - 1) / l);
        for(int j = 0; j < lim; j += l){
            int g = 1;
            for(int i = 0; i < m; ++i, g = 1ll * g * Gi % mod){
                int x = a[i + j], y = 1ll * g * a[i + j + m] % mod;
                a[i + j] = x + y;
                if(a[i + j] >= mod) a[i + j] -= mod;
                a[i + j + m] = x + mod - y;
                if(a[i + j + m] >= mod) a[i + j + m] -= mod;
            }
        }
    }
}
int n, m;
inline void mul_with_NTT(int *a, int *b, int n, int m,int *c){
    int lim = 1, len = 0;
    while(lim <= n + m) lim <<= 1, ++len;
    for(int i = 1; i < lim; ++i) to[i] = (to[i >> 1] >> 1) | ((i & 1) << len - 1);
    NTT(a, lim, 1); NTT(b, lim, 1);
    rep(i, 0, lim - 1) a[i] = 1ll * a[i] * b[i] % mod;
    NTT(a, lim, -1);
    const int inv = ksm(lim, mod - 2);
    rep(i, 0, n + m) c[i] = 1ll * a[i] * inv % mod;
}
/*
0 1
8
3 1
*/
signed main(){
    n = read(), m = read();
    rep(i, 0, n) a[i] = read();
    rep(i, 0, m) b[i] = read();
//    mul(a, b, n, m, c);
//    rep(i, 0, n) cout<<c[i]<<" "; cout<<endl;
    reverse(b, b + m + 1);
    int lim = 1, len = 0;
    while(lim <= n + m) lim <<= 1, ++len;
    rep(i, 0, lim - 1) to[i] = (to[i >> 1] >> 1) | ((i & 1) << len - 1);
    NTT(a, lim, 1); NTT(b, lim, 1);
    rep(i, 0, lim - 1) a[i] = 1ll * a[i] * b[i] % mod;
    NTT(a, lim, -1);
    const int inv = ksm(lim, mod - 2);
    rep(i, 0, lim - 1) a[i] = 1ll * a[i] * inv % mod;
    rep(i, m, m + n) cout<<a[i]<<" "; cout<<endl;
    gc(), gc();
    return 0;
}
原文地址:https://www.cnblogs.com/XiaoVsun/p/13054080.html