E Falfa with Substring
分析:
-
FFT 多项式乘法板子题 + 容斥
-
令 F k F_k Fk表示至少出现了 k k k个"bit"串的方案数
F k = ( k n − 2 k ) 2 6 n − 3 k F_k=(^{n-2k}_{k})26^{n-3k} Fk=(kn−2k)26n−3k
-
然后容斥一下得
a n s i = ∑ j ≥ k ( k j ) ( − 1 ) j − k F j = ∑ j ≥ k j ! k ! ( j − k ) ! ( − 1 ) j − k F j a n s i k ! = ∑ j ≥ k ( j ! F j ) ( ( − 1 ) j − k ( j − k ) ! ) \begin{aligned} ans_i&=&\sum_{j\geq k}(^{j}_{k})(-1)^{j-k}F_j\\ &=&\sum_{j\geq k}\frac{j!}{k!(j-k)!}(-1)^{j-k}F_j\\ {ans_i}{k!}&=&\sum_{j\geq k}(j!F_j)(\frac{(-1)^{j-k}}{(j-k)!}) \end{aligned} ansiansik!===j≥k∑(kj)(−1)j−kFjj≥k∑k!(j−k)!j!(−1)j−kFjj≥k∑(j!Fj)((j−k)!(−1)j−k)
k − j + j = k k-j+j=k k−j+j=k将 ( j ! F j ) (j!F_j) (j!Fj)看成 f n f_n fn , ( ( − 1 ) j − k ( j − k ) ! ) (\frac{(-1)^{j-k}}{(j-k)!}) ((j−k)!(−1)j−k)看成 g n g_n gn ,便可 n t t ntt ntt加速
#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int P(998244353), G(3), L(1 << 21);
inline void inc(int &x, int y) {
x += y;
if (x >= P) x -= P;
}
inline void dec(int &x, int y) {
x -= y;
if (x < 0) x += P;
}
inline int mod(int x) { return x % P; }
int fpow(int x, int k = P - 2) {
int r = 1;
for (; k; k >>= 1, x = 1LL * x * x % P) {
if (k & 1) r = 1LL * r * x % P;
}
return r;
}
int w[L], fac[L], ifac[L], inv[L], _ = [] {
w[L / 2] = 1;
for (int i = L / 2 + 1, x = fpow(G, (P - 1) / L); i < L; i++) w[i] = 1LL * w[i - 1] * x % P;
for (int i = L / 2 - 1; i >= 0; i--) w[i] = w[i << 1];
fac[0] = 1;
for (int i = 1; i < L; i++) fac[i] = 1LL * fac[i - 1] * i % P;
ifac[L - 1] = fpow(fac[L - 1]);
for (int i = L - 1; i; i--) {
ifac[i - 1] = 1LL * ifac[i] * i % P;
inv[i] = 1LL * ifac[i] * fac[i - 1] % P;
}
return 0;
}();
void dft(int *a, int n) {
//assert((n & n - 1) == 0);
for (int k = n >> 1; k; k >>= 1) {
for (int i = 0; i < n; i += k << 1) {
for (int j = 0; j < k; j++) {
int &x = a[i + j], y = a[i + j + k];
a[i + j + k] = 1LL * (x - y + P) * w[k + j] % P;
inc(x, y);
}
}
}
}
void idft(int *a, int n) {
//assert((n & n - 1) == 0);
for (int k = 1; k < n; k <<= 1) {
for (int i = 0; i < n; i += k << 1) {
for (int j = 0; j < k; j++) {
int x = a[i + j], y = 1LL * a[i + j + k] * w[k + j] % P;
a[i + j + k] = x - y < 0 ? x - y + P : x - y;
inc(a[i + j], y);
}
}
}
for (int i = 0, inv = P - (P - 1) / n; i < n; i++)
a[i] = 1LL * a[i] * inv % P;
std::reverse(a + 1, a + n);
}
inline int norm(int n) { return 1 << std::__lg(n * 2 - 1); }
struct Poly : public std::vector<int> {
#define T (*this)
using std::vector<int>::vector;
void append(const Poly &r) {
insert(end(), r.begin(), r.end());
}
int len() const { return size(); }
Poly operator-() const {
Poly r(T);
for (auto &x : r) x = x ? P - x : 0;
return r;
}
Poly &operator+=(const Poly &r) {
if (r.len() > len()) resize(r.len());
for (int i = 0; i < r.len(); i++) inc(T[i], r[i]);
return T;
}
Poly &operator-=(const Poly &r) {
if (r.len() > len()) resize(r.len());
for (int i = 0; i < r.len(); i++) dec(T[i], r[i]);
return T;
}
Poly &operator^=(const Poly &r) {
if (r.len() < len()) resize(r.len());
for (int i = 0; i < len(); i++) T[i] = 1LL * T[i] * r[i] % P;
return T;
}
Poly &operator*=(int r) {
for (int &x : T) x = 1LL * x * r % P;
return T;
}
Poly operator+(const Poly &r) const { return Poly(T) += r; }
Poly operator-(const Poly &r) const { return Poly(T) -= r; }
Poly operator^(const Poly &r) const { return Poly(T) ^= r; }
Poly operator*(int r) const { return Poly(T) *= r; }
Poly &operator<<=(int k) { return insert(begin(), k, 0), T; }
Poly operator<<(int r) const { return Poly(T) <<= r; }
Poly operator>>(int r) const { return r >= len() ? Poly() : Poly(begin() + r, end()); }
Poly &operator>>=(int r) { return T = T >> r; }
Poly pre(int k) const { return k < len() ? Poly(begin(), begin() + k) : T; }
friend void dft(Poly &a) { dft(a.data(), a.len()); }
friend void idft(Poly &a) { idft(a.data(), a.len()); }
friend Poly conv(const Poly &a, const Poly &b, int n) {
Poly p(a), q;
p.resize(n), dft(p);
p ^= &a == &b ? p : (q = b, q.resize(n), dft(q), q);
idft(p);
return p;
}
friend Poly operator*(const Poly &a, const Poly &b) {
int len = a.len() + b.len() - 1;
if (a.len() <= 16 || b.len() <= 16) {
Poly c(len);
for (int i = 0; i < a.len(); i++)
for (int j = 0; j < b.len(); j++)
c[i + j] = (c[i + j] + 1LL * a[i] * b[j]) % P;
return c;
}
return conv(a, b, norm(len)).pre(len);
}
#undef T
};
const int N=1e6+5, mo=998244353;
int ksm(int a,int b)
{
int res=1;
while(b)
{
if(b&1) (res*=a)%=mo;
a=a*a%mo; b>>=1;
}
return res;
}
int n;
int fc[N], infc[N];
void init()
{
fc[0]=1;
for(int i=1;i<=n;i++) fc[i]=fc[i-1]*i%mo;
infc[n]=ksm(fc[n],mo-2);
for(int i=n-1;i>=0;i--) infc[i]=infc[i+1]*(i+1)%mo;
}
int C(int n,int m)
{
return fc[n]*infc[m]%mo*infc[n-m]%mo;
}
Poly f,g;
void solve()
{
cin>>n;
init();
for(int i=0;i<=n;i++)
{
if(n>=3*i)
{
int t=fc[i]*ksm(26,n-3*i)%mo*C(n-2*i,i)%mo;
f.push_back(t);
}
else f.push_back(0);
}
for(int i=0;i<=n;i++)
{
int t=ksm(mo-1,i)*infc[i]%mo;
g.push_back(t);
}
reverse(g.begin(),g.end()); // f和g的下标同增,reverse f 或 g 都可
f=f*g;
for(int i=0;i<=n;i++)
{
cout<<f[i+n]*infc[i]%mo<<' ';
}cout<<"\n";
}
signed main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
solve();
}