luogu P4091 [HEOI2016/TJOI2016]求和
https://www.luogu.com.cn/problem/P4091
大力推式子
首先要知道
S
(
n
,
m
)
=
1
m
!
∑
i
=
0
m
(
−
1
)
m
−
i
C
m
i
i
n
S(n,m)=\frac{1}{m!}\sum\limits_{i=0}^m(-1)^{m-i}C_m^ii^n
S(n,m)=m!1i=0∑m(−1)m−iCmiin
具体证明的话可以把
m
n
=
∑
i
=
0
m
S
(
n
,
i
)
×
i
!
×
C
m
i
m^n=\sum\limits_{i=0}^mS(n,i)\times i!\times C_m^i
mn=i=0∑mS(n,i)×i!×Cmi二项式反演一下得到
然后开始推式子
f
(
n
)
=
∑
j
=
0
n
2
j
×
j
!
∑
i
=
0
n
S
(
i
,
j
)
f(n)=\sum\limits_{j=0}^n 2^j\times j!\sum\limits_{i=0}^n S(i,j)
f(n)=j=0∑n2j×j!i=0∑nS(i,j)
套上面那条狮子
=
∑
j
=
0
n
2
j
×
∑
i
=
0
n
∑
k
=
0
j
(
−
1
)
j
−
k
C
j
k
k
i
=\sum\limits_{j=0}^n 2^j\times \sum\limits_{i=0}^n\sum\limits_{k=0}^j(-1)^{j-k}C_j^k k^i
=j=0∑n2j×i=0∑nk=0∑j(−1)j−kCjkki
然后发现
i
i
i可以拉到后面去
=
∑
j
=
0
n
2
j
×
∑
k
=
0
j
(
−
1
)
j
−
k
C
j
k
∑
i
=
0
n
k
i
=\sum\limits_{j=0}^n 2^j\times \sum\limits_{k=0}^j(-1)^{j-k}C_j^k \sum\limits_{i=0}^n k^i
=j=0∑n2j×k=0∑j(−1)j−kCjki=0∑nki
可以把最后那坨设为
c
a
l
c
(
k
)
=
∑
i
=
0
n
k
i
calc(k)=\sum\limits_{i=0}^n k^i
calc(k)=i=0∑nki
=
∑
j
=
0
n
2
j
×
∑
k
=
0
j
(
−
1
)
j
−
k
j
!
k
!
(
j
−
k
)
!
c
a
l
c
(
k
)
=\sum\limits_{j=0}^n 2^j\times \sum\limits_{k=0}^j(-1)^{j-k}\frac{j!}{k!(j-k)!}calc(k)
=j=0∑n2j×k=0∑j(−1)j−kk!(j−k)!j!calc(k)
把
j
!
j!
j!提到前面然后大力卷积即可
大力NTT卷积即可
code:
#include<bits/stdc++.h>
#define N 400050
#define mod 998244353
using namespace std;
int add(int x, int y) { x += y;
if(x >= mod) x -= mod;
return x;
}
int sub(int x, int y) { x -= y;
if(x < 0) x += mod;
return x;
}
int mul(int x, int y) {
return 1ll * x * y % mod;
}
int qpow(int x, int y) {
int ret = 1;
for(; y; y >>= 1, x = mul(x, x)) if(y & 1) ret = mul(ret, x);
return ret;
}
const int G = 3;
const int G_inv = qpow(G, mod - 2);
int rev[N];
void ntt(int *a, int n, int o) {
for(int i = 1; i < n; i ++)
if(rev[i] > i) swap(a[i], a[rev[i]]);
for(int len = 2; len <= n; len <<= 1) {
int w0 = qpow(o == 1? G : G_inv, (mod - 1) / len);
for(int j = 0; j < n; j += len) {
int wn = 1;
for(int k = j; k < j + (len >> 1); k ++, wn = mul(wn, w0)) {
int X = a[k], Y = mul(wn, a[k + (len >> 1)]);
a[k] = add(X, Y), a[k + (len >> 1)] = sub(X, Y);
}
}
}
int ninv = qpow(n, mod - 2);
if(o == -1)
for(int i = 0; i < n; i ++) a[i] = mul(a[i], ninv);
}
int fac[N], ifac[N], mi[N];
void init(int n) {
fac[0] = mi[0] = 1;
for(int i = 1; i <= n; i ++) fac[i] = mul(fac[i - 1], i), mi[i] = mul(mi[i - 1], 2);
ifac[n] = qpow(fac[n], mod - 2);
for(int i = n - 1; i >= 0; i --) ifac[i] = mul(ifac[i + 1], i + 1);
}
int n, f[N], g[N];
int main() {
scanf("%d", &n);
init(n);
for(int i = 0; i <= n; i ++) f[i] = mul(qpow(mod - 1, i), ifac[i]);
g[0] = 1, g[1] = n + 1;
for(int i = 2; i <= n; i ++) g[i] = mul(sub(qpow(i, n + 1), 1), mul(qpow(i - 1, mod - 2), ifac[i]));
int len = 1;
for(; len <= n + n; len <<= 1);
for(int i = 1; i < len; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i&1) * (len >> 1));
ntt(f, len, 1), ntt(g, len, 1);
for(int i = 0; i < len; i ++) f[i] = mul(f[i], g[i]);
ntt(f, len, -1);
int ans = 0;
for(int i = 0; i <= n; i ++) ans = add(ans, mul(mi[i], mul(fac[i], f[i])));
printf("%d", ans);
return 0;
}