NOI 模拟 2019 Contest#18 A 【清华集训2016】如何优雅地求和 (数学)(多项式转下降幂)

传送门

按照题目给的启发,考虑证一下
n p = i = 0 n i ( n i ) p i ( 1 p ) n i np=\sum_{i=0}^ni\binom{n}{i}p^i(1-p)^{n-i}
= i = 1 n n ( n 1 ) ! ( n i ) ! ( i 1 ) ! p i ( 1 p ) n i =\sum_{i=1}^nn\frac{(n-1)!}{(n-i)!(i-1)!}p^i(1-p)^{n-i}
= n p i = 0 n 1 ( n 1 ) ! ( n 1 i ) ! i ! p i ( 1 p ) n i 1 = n p =np\sum_{i=0}^{n-1}\frac{(n-1)!}{(n-1-i)!i!}p^i(1-p)^{n-i-1}=np
类似这种简单情况,发现一个下降幂也是可以化简的
i = 0 n i k ( n i ) p i ( 1 p ) n i \sum_{i=0}^ni^{\underline k}\binom{n}{i}p^i(1-p)^{n-i}
= i = k n n k ( n k ) ! ( n i ) ! ( i k ) ! p i ( 1 p ) n i =\sum_{i=k}^n n^{\underline k}\frac{(n-k)!}{(n-i)!(i-k)!}p^i(1-p)^{n-i}
= n k p k i = 0 n k ( n k ) ! ( n k i ) ! i ! p i ( 1 p ) n i k = n k p k =n^{\underline k}p^k\sum_{i=0}^{n-k}\frac{(n-k)!}{(n-k-i)!i!}p^i(1-p)^{n-i-k}=n^{\underline k}p^k

于是只需要把点值转成下降幂的系数就可以了,先考虑系数转系数,斯特林数化简
a i x i = a i j = 0 i S i , j x j = j = 0 x j i = 0 n S i , j a i \sum a_ix^i=\sum a_i\sum_{j=0}^iS_{i,j}x^{\underline j}=\sum_{j=0}^{\infty}x^{\underline j}\sum_{i=0}^nS_{i,j}a_i
斯特林数用二项式反演展开
= j = 0 x j i = 0 n a i k = 0 j ( 1 ) k j ( j k ) k i =\sum_{j=0}^{\infty}x^{\underline j}\sum_{i=0}^na_i\sum_{k=0}^j(-1)^{k-j}\binom{j}{k}k^i
= j = 0 x j k = 0 j ( 1 ) k j ( j k ) i = 0 n a i k i =\sum_{j=0}^{\infty}x^{\underline j}\sum_{k=0}^j(-1)^{k-j}\binom{j}{k}\sum_{i=0}^na_ik^i
= j = 0 x j k = 0 j ( 1 ) k j ( j k ) f ( k ) =\sum_{j=0}^{\infty}x^{\underline j}\sum_{k=0}^j(-1)^{k-j}\binom{j}{k}f(k)
本来要多点求值的,但这道题已经帮你求好了,用 N T T NTT 优化即可

#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
    int cnt = 0, f = 1; char ch = 0;
    while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
    while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
    return cnt * f;
}
cs int N = 2e4 + 5;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
typedef long long ll;
int mul(int a, int b){ ll r=1ll*a*b; if(r<Mod) return r; return r%Mod; }
void Add(int &a, int b){ a = add(a, b); }
void Dec(int &a, int b){ a = dec(a, b); }
int ksm(int a, int b){ int ans=1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a); return ans; }
int n, m, x, a[N];
int fac[N], ifac[N];
#define poly vector<int> 
void prework(int n){
    fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
    for(int i = 2; i <= n; i++) fac[i] = mul(fac[i-1], i);
    ifac[n] = ksm(fac[n], Mod-2);
    for(int i = n-1; i >= 2; i--) ifac[i] = mul(ifac[i+1], i+1);
} 
int up, bit; poly rev;
void init(int deg){
    up = 1; bit = 0; while(up < deg) up <<= 1, ++bit; rev.resize(up);
    for(int i = 0; i < up; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<bit-1);
}
void NTT(poly &a, int typ){
    for(int i = 0; i < up; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
    for(int i = 1; i < up; i <<= 1){
        int wn = ksm(3, (Mod-1)/(i<<1));
        for(int j = 0; j < up; j += (i<<1))
        for(int k = 0, w = 1; k < i; ++k, w=mul(w,wn)){
            int x = a[k+j], y = mul(w, a[k+j+i]);
            a[k+j] = add(x, y); a[k+j+i] = dec(x, y);
        }
    }
    if(typ == -1){
        reverse(a.begin()+1, a.end());
        for(int i=0,iv=ksm(up,Mod-2); i<up; i++) a[i] = mul(a[i], iv);
    }
}
int main(){
    n = read(), m = read(), x = read(); prework(m);
    for(int i = 0; i <= m; i++) a[i] = read();
    if(m <= 5000){
        int coef = 1, ans = 0;
        for(int i = 0; i <= m; i++){
            int sum = 0;
            for(int j = 0; j <= i; j++){
                int ret = mul(mul(ifac[j], ifac[i-j]), a[j]);
                (i-j)&1 ? Dec(sum, ret) : Add(sum, ret);
            } Add(ans, mul(coef, sum));
            coef = mul(coef, mul(n-i, x));
        } cout << ans; return 0;
    }
    else{
        poly f, g; f.resize(m+1); g.resize(m+1);
        for(int i = 0; i <= m; i++) f[i] = mul(a[i], ifac[i]);
        for(int i = 0; i <= m; i++) g[i] = i&1 ? Mod-ifac[i] : ifac[i];
        init(m+m+1); f.resize(up); g.resize(up); NTT(f, 1); NTT(g, 1);
        for(int i = 0; i < up; i++) f[i] = mul(f[i], g[i]);
        NTT(f, -1); f.resize(m+1);
        int coef = 1, ans = 0;
        for(int i = 0; i <= m; i++){
            Add(ans, mul(coef, f[i]));
            coef = mul(coef, mul(n-i, x));
        } cout << ans; return 0;  
    }
}

发布了610 篇原创文章 · 获赞 94 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/103622726
今日推荐