BZOJ4555 求和

题面

解:把第二类斯特林数和组合数拆开。

惊讶的发现推不下去了......后面那个i的∑跟j有关,不能卷积。

这时发现一开始的式子,j的上界可以改为n。

于是这里i的下界改为1。就是一个常数,可以卷积。

卷积出来之后枚举j即可。

  1 #include <bits/stdc++.h>
  2 
  3 typedef long long LL;
  4 
  5 const int N = 100010, MO = 998244353;
  6 
  7 int A[N << 2], B[N << 2], r[N << 2];
  8 int fac[N], inv[N], invn[N];
  9 
 10 inline int qpow(int a, int b) {
 11     int ans = 1;
 12     while(b) {
 13         if(b & 1) ans = 1ll * ans * a % MO;
 14         a = 1ll * a * a % MO;
 15         b = b >> 1;
 16     }
 17     return ans;
 18 }
 19 
 20 inline void prework(int n) {
 21     static int R = 0;
 22     if(R == n) return;
 23     R = n;
 24     int lm = 1;
 25     while((1 << lm) < n) lm++;
 26     for(int i = 1; i < n; i++) {
 27         r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1));
 28     }
 29     return;
 30 }
 31 
 32 inline void NTT(int *a, int n, int f) {
 33     prework(n);
 34     for(int i = 0; i < n; i++) {
 35         if(i < r[i]) std::swap(a[i], a[r[i]]);
 36     }
 37     for(int len = 1; len < n; len <<= 1) {
 38         int Wn = qpow(3, (MO - 1) / (len << 1));
 39         if(f == -1) Wn = qpow(Wn, MO - 2);
 40         for(int i = 0; i < n; i += (len << 1)) {
 41             int w = 1;
 42             for(int j = 0; j < len; j++) {
 43                 int t = 1ll * a[i + len + j] * w % MO;
 44                 a[i + len + j] = (a[i + j] - t) % MO;
 45                 a[i + j] = (a[i + j] + t) % MO;
 46                 w = 1ll * w * Wn % MO;
 47             }
 48         }
 49     }
 50     if(f == -1) {
 51         int inv = qpow(n, MO - 2);
 52         for(int i = 0; i < n; i++) {
 53             a[i] = 1ll * a[i] * inv % MO;
 54         }
 55     }
 56     return;
 57 }
 58 
 59 inline int C(int n, int m) {
 60     if(n < 0 || m < 0 || n < m) return 0;
 61     return 1ll * fac[n] * invn[m] % MO * invn[n - m] % MO;
 62 }
 63 
 64 inline int getQ(int a, int q, int n) {
 65     if(q == 1) {
 66         return 1ll * a * n % MO;
 67     }
 68     else {
 69         return 1ll * a * (qpow(q, n) - 1) % MO * qpow(q - 1, MO - 2) % MO;
 70     }
 71 }
 72 
 73 int main() {
 74     int n;
 75     scanf("%d", &n);
 76     fac[0] = inv[0] = invn[0] = 1;
 77     fac[1] = inv[1] = invn[1] = 1;
 78     for(int i = 2; i <= n; i++) {
 79         fac[i] = 1ll * fac[i - 1] * i % MO;
 80         inv[i] = 1ll * inv[MO % i] * (MO - MO / i) % MO;
 81         invn[i] = 1ll * invn[i - 1] * inv[i] % MO;
 82     }
 83 
 84     /// solve
 85     for(int i = 0; i <= n; i++) {
 86         A[i] = invn[i] * ((i & 1) ? -1 : 1);
 87         B[i] = 1ll * invn[i] * getQ(1, i, n + 1) % MO;
 88     }
 89     int len = 1;
 90     while(len <= n * 2) len <<= 1;
 91     NTT(A, len, 1); NTT(B, len, 1);
 92     for(int i = 0; i < len; i++) {
 93         A[i] = 1ll * A[i] * B[i] % MO;
 94     }
 95     NTT(A, len, -1);
 96 
 97     int ans = 0;
 98     for(int i = 0; i <= n; i++) {
 99         ans = (ans + 1ll * fac[i] * qpow(2, i) % MO * A[i] % MO) % MO;
100     }
101     printf("%d\n", (ans + MO) % MO);
102     return 0;
103 }
AC代码

 解法二:资料1资料2

转载于:https://www.cnblogs.com/huyufeifei/p/10886941.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值