LuoguP5488 差分与前缀和 (多项式 组合数学 生成函数)

image

前置知识:
二项式定理
image
杨辉三角 第n行第m个数为C n-1, m-1
image

  • 把前缀和 化成卷积的形式:
    image
    这时一个斜着的杨辉三角
    image
    image

现在我们知道了两种情况下b[i]的系数,因为是组合数,k超级大,所以递推出每一个bi.

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define int long long
const int N = 1e5 + 5;
const int M = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1004535809;
const double PI = acos(-1.0);
ll a[N << 2], b[N << 2];
int limit, L, RR[N << 2];
ll qpow(ll a, ll b)
{
    ll res = 1;
    while(b) {
        if(b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res % mod;
}
const int G = 3;
ll inv(ll x) {return qpow(x, mod - 2);}
void NTT(ll *A, int type)
{
    for(int i = 0; i < limit; ++ i)
        if(i < RR[i])
            swap(A[i], A[RR[i]]);
    for(int mid = 1; mid < limit; mid <<= 1) {//原根代替单位根
        //ll wn = qpow(type == 1 ? G : Gi, (p - 1) / (mid << 1));
        ll wn = qpow(G, (mod - 1) / (mid * 2));
        if(type == -1) wn = qpow(wn, mod - 2); //wn的-1次方
        //如果超时了上面if这句话删掉,在下面的if(type == -1)里加上下面这个循环
        /*for (int i = 1; i < limit / 2; i ++)
        swap(A[i], A[limit - i]); */
        //逆变换则乘上逆元,因为我们算出来的公式中逆变换是(a^-ij),也就是(a^ij)的逆元
        for(int pos = 0; pos < limit; pos += mid * 2) {
            ll w = 1;
            for(int j = 0; j < mid; ++ j, w = (w * wn) % mod) {
                int x = A[pos + j], y = w * A[pos + mid + j] % mod;
                A[pos + j] = (x + y) % mod;
                A[pos + j + mid] = (x - y + mod) % mod;

            }
        }
    }

    if(type == -1) {
        ll limit_inv = inv(limit);//N的逆元(N是limit, 指的是2的整数幂)
        for(int i = 0; i < limit; ++ i)
            A[i] = (A[i] * limit_inv) % mod;//NTT还是要除以n的,但是这里把除换成逆元了,inv就是n在模p意义下的逆元
    }
}
void poly_mul(ll *a, ll *b, int deg)
{
    for(limit = 1, L = 0; limit <= deg; limit <<= 1) L ++ ;
    for(int i = 0; i < limit; ++ i) {
        RR[i] = (RR[i >> 1] >> 1) | ((i & 1) << (L - 1));
    }
    NTT(a, 1);
    NTT(b, 1);
    for(int i = 0; i < limit; ++ i) a[i] = a[i] * b[i] % mod;
    NTT(a, -1);
}
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0', s %= mod, ch=getchar();
    return s*w;
}
signed main () {

    ll n, k, opt;
    n = read(), k =read(), opt = read();
    -- n;
    for ( int i = 0; i <= n; ++ i ) {
        a[i] = read();
    }
    b[0] = 1;
    if ( !opt ) {
        for ( int i = 1; i <= n; ++ i ) {
            b[i] = b[i - 1] * qpow( i, mod - 2) % mod * (k + i - 1) % mod;
        }
    } else {
        for ( int i = 1; i <= n; ++ i ) {
            b[i] = (b[i - 1] * qpow( i, mod - 2) % mod * ( k - i + 1) % mod * -1 + mod) % mod;
        }
    }
    poly_mul(a, b, n + n);
    for ( int i = 0; i <= n; ++ i ) cout << a[i] << ' ';
    return 0;
}
posted @ 2022-05-03 21:41  qingyanng  阅读(26)  评论(0编辑  收藏  举报