zoukankan      html  css  js  c++  java
  • [HEOI2016/TJOI2016] 求和

    有关斯特林数的介绍和斯特林反演:斯特林数及斯特林反演

    本来是想做容斥的,结果发现了一个多项式题目……

    不过容斥和反演息息相关嘛。

    这题做完之后感觉卷积也不是那么难,就把它理解成一个预处理一个复杂函数的方法就好了。这样复杂度可以从 (O(n)) 求和式变成 (O(1)) 取得函数值了。

    这道题目是有关第二类斯特林数的,上文的博客中推导了第二类斯特林数的一个公式:

    (egin{aligned} displaystyle S(n, m) = frac{1}{m!} sum_{k = 0}^m (-1)^k C(m, k) (m - k)^n \ displaystyle = sum_{k = 0}^m frac{(-1)^k (m - k)^n}{k!(m - k)!} end{aligned})

    发现上式是个卷积形式,于是本题的柿子可以这样推导(后两步好神仙啊):

    (egin{aligned} displaystyle F(n) =sum_{i=0}^n sum_{j=0}^i S(i, j) * 2^j * j! \ displaystyle =sum_{i=0}^n sum_{j=0}^n S(i, j) * 2^j*j! \ displaystyle =sum_{j=0}^n 2^j*j!sum_{i=0}^n S(i, j) \ displaystyle =sum_{j=0}^n 2^j*j!sum_{i=0}^n sum_{k=0}^jfrac{(-1)^k}{k!}cdotfrac{(j-k)^i}{(j-k)!} \ displaystyle =sum_{j=0}^n 2^j*j!sum_{k=0}^jfrac{(-1)^k}{k!}cdotfrac{ sum_{i=0}^n (j-k)^i}{(j-k)!} \ displaystyle =sum_{j=0}^n 2^j*j!sum_{k=0}^jfrac{(-1)^k}{k!}cdot frac{(j-k)^{n+1}-1}{(j-k-1)(j-k)!} \ end{aligned})

    这样,这道题目的柿子也化成了卷积形式:

    (egin{aligned} displaystyle f(x) = frac{(-1)^x}{x!} \ displaystyle g(x) = frac{x^{n+1}-1}{(x-1)*x!} \ displaystyle F(n) = sum_{i = 0}^{n} 2^i * i! *(f×g)(i) end{aligned})

    可以用 (NTT) 求解 …… 抄抄抄

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int mod = 998244353;
    const int maxn = 400000 + 10;
    int n, len, rado, limit, r[maxn], fac[maxn], inv[maxn], f[maxn], g[maxn], pow_2[maxn], ans;
    
    inline int Fast_pow(int x, int p) {
      register int res = 1;
      for( ; p; x = 1ll * x * x % mod, p = p >> 1) if( p & 1 ) res = 1ll * x * res % mod;
      return res;
    }
    
    inline void Fast_numbertheory_transform(int *a, int type) {
      for(int i = 0; i < limit; ++i) if( i < r[i] ) swap(a[i], a[r[i]]);
      for(int mid = 1; mid < limit; mid = mid << 1) {
        int Base_p = Fast_pow(3ll, (mod - 1) / (mid << 1));
        if( type == -1 ) Base_p = Fast_pow(Base_p, mod - 2);
        for(int l = 0, length = mid << 1; l < limit; l = l + length) {
          for(int k = 0, p = 1; k < mid; ++k, p = 1ll * p * Base_p % mod) {
            int x = a[l + k], y = 1ll * p * a[l + mid + k] % mod;
            a[l + k] = (x + y) % mod, a[l + mid + k] = (x - y + mod) % mod;
          }
        }
      }
      int inver = Fast_pow(limit, mod - 2);
      if( type == -1 ) for(int i = 0; i < limit; ++i) a[i] = 1ll * a[i] * inver % mod;
    }
    
    
    int main(int argc, char const *argv[])
    {
      scanf("%d", &n), pow_2[0] = fac[0] = fac[1] = 1;
      for(int i = 1; i <= n; ++i) pow_2[i] = (pow_2[i - 1] << 1) % mod;
      for(int i = 2; i <= n; ++i) fac[i] = 1ll * i * fac[i - 1] % mod;
      inv[n] = Fast_pow(fac[n], mod - 2);
      for(int i = n; i >= 1; --i) inv[i - 1] = 1ll * inv[i] * i % mod;
      g[0] = 1, g[1] = n + 1;
      for(int i = 0; i <= n; ++i) f[i] = 1ll * ((i & 1) ? mod - 1 : 1) * inv[i] % mod;
      for(int i = 2; i <= n; ++i) g[i] = 1ll * (Fast_pow(i, n + 1) - 1 + mod) * Fast_pow(i - 1 + mod, mod - 2) % mod * inv[i] % mod;
      len = n << 1, rado = 0, limit = 1;
      while( limit < len ) limit = (limit << 1), ++rado;
      for(int i = 0; i < limit; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (rado - 1));
      Fast_numbertheory_transform(f, 1);
      Fast_numbertheory_transform(g, 1);
      for(int i = 0; i < limit; ++i) f[i] = 1ll * f[i] * g[i] % mod;
      Fast_numbertheory_transform(f, -1);
      for(int i = 0; i <= n; ++i) ans = (ans + 1ll * fac[i] * pow_2[i] % mod * f[i] % mod) % mod;
      printf("%d
    ", ans);
    
      return 0;
    }
    
  • 相关阅读:
    洛谷【P1109 学生分组】 题解
    卡特兰数
    并查集
    深度优先搜索DFS;递归
    【71】序列模型和注意力机制
    c/c++ 常用的几个安全函数
    win32 Ui 编程 收集
    vc获取特殊路径(SpecialFolder)
    std::map 自定义排序
    16-----BBS论坛
  • 原文地址:https://www.cnblogs.com/nanjoqin/p/11379230.html
Copyright © 2011-2022 走看看