タイトル
解析中
$ S $回に表示される少なくとも$ i $色のスキームの数を$ f_i $とし、$ i $色が$ S $回表示されることを指定します。残りはオプションです。$ f_i = \ binom {m} {i } * \ frac {n!} {(S!)^ i(n-iS)!} *(mi)^ {n-iS} $、そのうち$ \ frac {n!} {(S!)^ i( n-iS)!} $は、$ n $位置で$ n-iS $位置を選択し、$ i $色を入力し、各色の計画数を$ S $回入力することを意味します。
$ g_i $を設定することは、$ S $の発生の色が$ i $スキームの数と正確に一致することを意味し、$ f_i = \ sum_ {j = i} \ binom {j} {i} g_j $
したがって、二項反転が利用可能です:$$ \ 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 *} $$
たたみ込みは
$ O(M \ log M)$
コード:
#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 ' ; ret * fを返します。 } int add(int x、int y) { return x + y <mod?x + y:x + y- mod; } int rdc(int x、 { 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 ; } 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 ; 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 [xy]%mod; } void NTT_init(int x) { lim = 1 ; ビット = 0 ; while(lim <= x) { lim<< = 1 ; ++ ビット; } for(int i = 1 ; i <lim; ++ i) rev [i] =(rev [i >> 1 ] >> 1)| ((i&1)<<(ビット-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); 初期化(); for(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; 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); 0を返し ます。 }