luogu P6667 [清华集训2016] 如何优雅地求和
https://www.luogu.com.cn/problem/P6667
和20年省选很像,一下子没想出来怎么做,还是不够熟练
\(f\)由点值给出,考虑到后面有组合数,还有幂函数,不妨考把\(f\)写成下降幂多项式的形式
\(\sum\limits_{k=0}^n\binom{n}{k}x^k(1-x)^{n-k}\sum\limits_{i=0}^mf[i]k^{\underline{i}}\)
\(=\sum\limits_{i=0}^mf[i]\sum\limits_{k=i}^nk^{\underline{i}}\binom{n}{k}x^k(1-x)^{n-k}\)
因为当\(k<i\)的时候下降幂为0,所以\(k\)从\(i\)开始
\(=\sum\limits_{i=0}^mf[i]\sum\limits_{k=i}^n\frac{k!}{(k-i)!}\frac{n!}{k!(n-k)!}x^k(1-x)^{n-k}\)
\(=\sum\limits_{i=0}^mf[i]n^{\underline{i}}\sum\limits_{k=i}^n\frac{(n-i)!}{(k-i)!(n-k)!}x^k(1-x)^{n-k}\)
\(=\sum\limits_{i=0}^mf[i]n^{\underline{i}}\sum\limits_{k=i}^n\frac{(n-i)!}{(k-i)!(n-k)!}x^k(1-x)^{n-k}\)
\(=\sum\limits_{i=0}^mf[i]n^{\underline{i}}\sum\limits_{k=i}^n\binom{n-i}{k-i}x^k(1-x)^{n-k}\)
\(=\sum\limits_{i=0}^mf[i]n^{\underline{i}}\sum\limits_{k=0}^{n-i}\binom{n-i}{k}x^{k+i}(1-x)^{n-i-k}\)
提一个\(x^i\)出去
\(=\sum\limits_{i=0}^mf[i]n^{\underline{i}} x^i\sum\limits_{k=0}^{n-i}\binom{n-i}{k}x^{k}(1-x)^{n-i-k}\)
容易发现右边就是个二项式定理,值为1
\(=\sum\limits_{i=0}^mf[i]n^{\underline{i}} x^i\)
所以我们要求的实际上是这么个东西
把\(f[i]\)用下降幂多项式乘法中的IDFT求出来即可
即把点值的\(EGF\)卷上一个\(e^{-x}\)
code:
#include<bits/stdc++.h>
#define mod 998244353
#define N 800050
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;
}
int fac[N], ifac[N];
void init(int n) {
fac[0] = 1;
for(int i = 1; i <= n; i ++) fac[i] = mul(fac[i - 1], i);
ifac[n] = qpow(fac[n], mod - 2);
for(int i = n - 1; i >= 0; i --) ifac[i] = mul(ifac[i + 1], i + 1);
}
const int G = 3;
const int Ginv = qpow(3, mod - 2);
int rev[N];
void ntt(int *a, int n, int o) {
for(int i = 1; i < n; i ++) if(i > rev[i]) swap(a[i], a[rev[i]]);
for(int len = 2; len <= n; len <<= 1) {
int w0 = qpow((o == 1)? G : Ginv, (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 a[N], b[N], ex[N], efx[N];
void DFT(int *a, int n) {
ntt(a, n, 1);
for(int i = 0; i < n; i ++) a[i] = mul(a[i], ex[i]);
ntt(a, n, -1);
}
void IDFT(int *a, int n) {
ntt(a, n, 1);
for(int i = 0; i < n; i ++) a[i] = mul(a[i], efx[i]);
ntt(a, n, -1);
}
int n, m, x;
int main() {
scanf("%d%d%d", &n, &m, &x);
init(m * 2);
for(int i = 0; i <= m; i ++) scanf("%d", &a[i]), a[i] = mul(a[i], ifac[i]);
for(int i = 0; i <= m; i ++) {
efx[i] = ex[i] = ifac[i];
if(i & 1) efx[i] = sub(0, efx[i]);
}
// for(int i = 0; i <= m; i ++) printf("%d ", a[i]); printf("\n");
int len = 1;
for(; len <= 2 * m; len <<= 1);
for(int i = 1; i < len; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) * (len >> 1));
ntt(efx, len, 1);
IDFT(a, len);
// for(int i = 0; i <= m; i ++) printf("%d ", a[i]); printf(" %d\n", len);
int pw = 1, xjm = 1, ans = 0;
for(int i = 0; i <= m; i ++) {
ans = add(ans, mul(a[i], mul(xjm, pw)));
pw = mul(pw, x), xjm = mul(xjm, n - i);
}
printf("%d", ans);
return 0;
}