Titulo
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; }