[HAOI2018] Dyeing-Binomial inversion

Title

  LOJ2527

Parsing

  Let the number of schemes with at least $ i $ colors appear in $ S $ times be $ f_i $, and specify that $ i $ colors appear in $ S $ times, the remaining optional: $ f_i = \ binom {m} {i } * \ frac {n!} {(S!) ^ i (n-iS)!} * (mi) ^ {n-iS} $, of which $ \ frac {n!} {(S!) ^ i ( n-iS)!} $ means to select $ n-iS $ positions in $ n $ positions, fill in $ i $ colors, and fill in the number of plans for each color $ S $ times.

  Setting $ g_i $ means that the color of the occurrence of $ S $ has exactly the number of $ i $ schemes, and then you will find $ f_i = \ sum_ {j = i} \ binom {j} {i} g_j $

  So the binomial inversion is available: $$ \ begin {align *} g_i & = \ sum_ {j = i} (-1) ^ {ji} \ binom {j} {i} f_j \\ & = \ frac { 1} {i!} \ Sum_ {j = i} \ frac {(-1) ^ {ji}} {(ji)!} * J! * F_j \ end {align *} $$

  Convolution can be

  $O(M \log M)$

 Code:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 200005, mod = 1004535809, g = 3;

inline int read()
{
    int ret, f=1;
    char c;
    while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')f=-1;
    ret=c-'0';
    while((c=getchar())&&(c>='0'&&c<='9'))ret=(ret<<3)+(ret<<1)+c-'0';
    return ret*f;
}

int add ( int x, int y)
{
    return x + y < mod? x + y: x + y - mod;
}

int rdc(int x, int y)
{
    return x - y < 0 ? x - y + mod: x - y;
}

ll qpow(ll x, int y)
{
    ll ret = 1;
    while(y)
    {
        if(y&1)
            ret = ret * x% mod;
        x = x * x % mod;
        y >>= 1;
    }
    return right;
}

int n, m, s, lim, bit, rev[maxn<<1];
int fac[10000005], fnv[10000005], a[maxn];
ll ginv, f[maxn<<1], h[maxn<<1];

void init()
{
    int t = max(n, m);
    ginv = qpow(g, mod - 2);
    fac[0] = 1;
    for(int i = 1; i <= t; ++i)
        fac [i] = 1LL * fac [i- 1 ] * i% mod;
    fnv[t] = qpow(fac[t], mod - 2);
    for(int i = t - 1; i >= 0; --i)
        fnv [i] = 1LL * fnv [i + 1 ] * (i + 1 )% mod;
}

int comb(int x, int y)
{
    if(x < y || y < 0)    return 0;
    return (1LL * fac[x] * fnv[y] % mod) * fnv[x-y] % mod;
}

void NTT_init(int x)
{
    lim = 1 ;
    bit = 0;
    while(lim <= x)
    {
        lim <<= 1;
        ++ bit;
    }
    for(int i = 1; i < lim; ++i)
        rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (bit - 1));
}

void NTT(ll *x, int y)
{
    for(int i = 1; i < lim; ++i)
        if(i < rev[i])
            swap(x[i], x[rev[i]]);
    ll wn, w, u, v;
    for(int i = 1; i < lim; i <<= 1)
    {
        wn = qpow((y == 1)? g: ginv, (mod - 1) / (i << 1));
        for(int j = 0; j < lim; j += (i << 1))
        {
            w = 1;
            for(int k = 0; k < i; ++k)
            {
                u = x[j+k];
                v = x[j+k+i] * w % mod;
                x[j+k] = add(u, v);
                x[j+k+i] = rdc(u, v);
                w = w * wn % mod;
            }
        }
    }
    if(y == -1)
    {
        ll linv = qpow(lim, mod - 2);
        for(int i = 0; i < lim; ++i)
            x[i] = x[i] * linv % mod;
    }
}

int main ()
{
    n = read(); m = read(); s = read();
    for(int i = 0; i <= m; ++i)
        a[i] = read();
    int sj = min(m, n / s);
    init();
    for(int i = 0; i <= sj; ++i)
        f[i] = (((1LL * comb(m, i) * fac[n] % mod) * qpow(fnv[s], i) % mod) * fnv[n-i*s] % mod) * qpow(m - i, n - i * s) % mod;
    for(int i = 0; i <= sj; ++i)
    {
        f[i] = f[i] * fac[i] % mod;
        h[sj-i] = ((i & 1)? rdc(0, fnv[i]): fnv[i]);
    }
    NTT_init(sj << 1);
    NTT(f, 1);
    NTT(h, 1);
    for(int i = 0; i < lim; ++i)
        f[i] = f[i] * h[i] % mod;
    NTT(f, -1);
    int ans = 0;
    for(int i = 0; i <= sj; ++i)
        ans = add(ans, (a[i] * f[i+sj] % mod) * fnv[i] % mod);
    printf("%d", ans);
    return 0;
}
View Code

Guess you like

Origin www.cnblogs.com/Joker-Yza/p/12676726.html