E Falfa with Substring

44 篇文章 0 订阅
21 篇文章 0 订阅

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=(kn2k)26n3k

  • 然后容斥一下得
    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!===jk(kj)(1)jkFjjkk!(jk)!j!(1)jkFjjk(j!Fj)((jk)!(1)jk)
    k − j + j = k k-j+j=k kj+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)!}) ((jk)!(1)jk)看成 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();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yezzz.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值