[HAOI2018] Teñido-inversión binomial

Titulo

  LOJ2527

Analizando

  Deje que la cantidad de esquemas con al menos $ i $ colores aparezca en $ S $ veces $ f_i $, y especifique que $ i $ colores aparezcan en $ S $ veces, el resto opcional: $ f_i = \ binom {m} {i } * \ frac {n!} {(S!) ^ i (n-iS)!} * (mi) ^ {n-iS} $, de los cuales $ \ frac {n!} {(S!) ^ i ( n-iS)!} $ significa seleccionar $ n-iS $ posiciones en $ n $ posiciones, completar $ i $ colores y completar el número de planes para cada color $ S $ veces.

  Establecer $ g_i $ significa que el color de la ocurrencia de $ S $ tiene exactamente el número de esquemas $ i $, y luego encontrará $ f_i = \ sum_ {j = i} \ binom {j} {i} g_j $

  Entonces la inversión binomial está disponible: $$ \ 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 *} $$

  La convolución puede ser

  $ O (M \ log M) $

 Código:

#include <cstdio> 
#include <iostream> 
#include <algorithm> 
#include <cstring>
 usando el  espacio de nombres std; 
typedef largo  largo 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 ' ;
    volver ret * f; 
} 

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

int rdc ( int x,
{ 
    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 ret; 
} 

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 ;
    para ( int i = 1 ; i <= t; ++ i) 
        fac [i] = 1LL * fac [i- 1 ] * i% mod; 
    fnv [t] = qpow (fac [t], mod - 2 );
    para ( 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 )     devuelve  0 ;
    return (1LL * fac [x] * fnv [y]% mod) * fnv [xy]% mod; 
} 

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

nulo 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; 
    para ( int i = 1; yo <lim; i << = 1 ) 
    { 
        wn = qpow ((y == 1 )? g: ginv, (mod - 1 ) / (i << 1 ));
        para ( int j = 0 ; j <lim; j + = (i << 1 )) 
        { 
            w = 1 ;
            para ( int k = 0 ; k <i; ++ k) 
            { 
                u = x [j + k]; 
                v = x [j + k + i] * w% mod; 
                x [j + k] =agregar (u, v); 
                x [j + k + i] = rdc (u, v); 
                w = w * wn% mod; 
            } 
        } 
    } 
    if (y == - 1 ) 
    { 
        ll linv = qpow (lim, mod - 2 );
        para ( int i = 0 ; i <lim; ++ i) 
            x [i] = x [i] * linv% mod; 
    } 
} 

int main () 
{ 
    n = read (); m = leer (); s = leer ();
    para ( int i =0 ; i <= m; ++ i) 
        a [i] = leer ();
    int sj = min (m, n / s); 
    en eso(); 
    para ( int i = 0 ; i <= sj; ++ i) 
        f [i] = (((1LL * comb (m, i) * fac [n]% mod) * qpow (fnv [s], i) % mod) * fnv [ni * s]% mod) * qpow (m - i, n - i * s)% mod;
    para ( 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 );
    para ( int i = 0 ; i <lim; ++ i) 
        f [i] = f [i] * h [i]% mod; 
    NTT (f, - 1 );
    int ans = 0 ;
    para ( int i = 0 ; i <= sj; ++ i) 
        ans = add (ans, (a [i] * f [i + sj]% mod) * fnv [i]% mod); 
    printf ( " % d " , ans);
    volver  0; 
}
Ver código

Supongo que te gusta

Origin www.cnblogs.com/Joker-Yza/p/12676726.html
ido
Recomendado
Clasificación