BZOJ传送门
洛谷传送门
解析:
令 N = min ( ⌊ n s ⌋ , m ) N=\min(\lfloor\frac{n}{s}\rfloor,m) N=min(⌊sn⌋,m),显然最多只可能有 N N N种颜色恰好被染成 s s s块。
考虑将恰好有 k k k种被染成 s s s块的颜色转化成至少有 k k k种被染成 s s s块的颜色来容斥。
设这个数为 f k f_k fk,现在考虑凑出 f k f_k fk。
首先选择 i i i种颜色 ( m i ) {m\choose i} (im),然后选择 i s is is个位置 ( n i s ) {n\choose is} (isn),在这 i s is is个位置上做可重集的全排列 ( i s ) ! ( s ! ) i \frac{(is)!}{(s!)^i} (s!)i(is)!,然后剩下的 n − i s n-is n−is个位置每一个有 m − i m-i m−i种颜色可以选择。
我们得到 f i = ( m i ) ( n i s ) ( i s ) ! ( s ! ) i ( n − i s ) m − i f_i={m\choose i}{n\choose is}\frac{(is)!}{(s!)^i}(n-is)^{m-i} fi=(im)(isn)(s!)i(is)!(n−is)m−i
然后常规容斥:
f i = ∑ j = i N a n s j a n s i = ∑ j = i N ( − 1 ) j − i ( j i ) f j f_i=\sum_{j=i}^Nans_j\\ans_i=\sum_{j=i}^N(-1)^{j-i}{j\choose i}f_j fi=j=i∑Nansjansi=j=i∑N(−1)j−i(ij)fj
然后展开:
a
n
s
i
=
∑
j
=
i
N
(
−
1
)
j
−
i
j
!
(
j
−
i
)
!
i
!
f
j
a
n
s
i
∗
i
!
=
∑
j
=
i
N
(
−
1
)
j
−
i
(
j
−
i
)
!
f
j
j
!
\begin{aligned} ans_i&=&&\sum_{j=i}^N(-1)^{j-i}\frac{j!}{(j-i)!i!}f_j\\ ans_i*i!&=&&\sum_{j=i}^N\frac{(-1)^{j-i}}{(j-i)!}f_jj! \end{aligned}
ansiansi∗i!==j=i∑N(−1)j−i(j−i)!i!j!fjj=i∑N(j−i)!(−1)j−ifjj!
令 F ( x ) = ∑ ( − 1 ) i i ! x i , G ( x ) = ∑ f j j ! F(x)=\sum \frac{(-1)^i}{i!}x^i,G(x)=\sum f_jj! F(x)=∑i!(−1)ixi,G(x)=∑fjj!
我们将 G G G翻转一下就可以做卷积了。
然后将结果数组翻转就可以和原数组 w w w做点值乘法得到答案了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int mod=1004535809;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int quickpow(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))if(b&1)res=mul(res,a);return res;}
inline void NTT(int *A,int len,int typ){
static int r[1<<18];
for(int re i=0;i<len;++i)r[i]=r[i>>1]>>1|((i&1)*len>>1);
for(int re i=0;i<len;++i)if(i<r[i])swap(A[i],A[r[i]]);
for(int re i=1;i<len;i<<=1){
re int wn=quickpow(typ==1?3:(mod+1)/3,(mod-1)/i/2);
for(int re j=0;j<len;j+=i<<1){
int w=1;
for(int re k=0;k<i;++k,w=mul(w,wn)){
int re x=A[j+k],y=mul(w,A[j+k+i]);
A[j+k]=add(x,y);
A[j+k+i]=dec(x,y);
}
}
}
if(typ==-1)for(int re i=0,inv=quickpow(len,mod-2);i<len;++i)A[i]=mul(A[i],inv);
}
int F[1<<18],G[1<<18];
cs int M=100005;
cs int P=1e7+7;
int n,m,N,S;
int w[M];
int fac[P],inv[P],ifac[P];
int f[M];
inline int C(int n,int m){
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
signed main(){
n=getint(),m=getint(),S=getint();
N=min(n/S,m);
for(int re i=0;i<=m;++i)w[i]=getint();
fac[0]=fac[1]=inv[0]=inv[1]=ifac[0]=ifac[1]=1;
for(int re i=2;i<=max(n,m);++i){
fac[i]=mul(fac[i-1],i);
inv[i]=mul(mod-mod/i,inv[mod%i]);
ifac[i]=mul(ifac[i-1],inv[i]);
}
for(int re i=0,coef=1;i<=N;++i,coef=mul(coef,ifac[S]))f[i]=mul(mul(C(m,i),C(n,S*i)),mul(quickpow(m-i,n-i*S),mul(fac[i*S],coef)));
for(int re i=0;i<=N;++i){
F[i]=mul(ifac[i],(i&1)?mod-1:1);
G[i]=mul(f[i],fac[i]);
}
reverse(G,G+N+1);
int len=1;
while(len<=(N<<1))len<<=1;
NTT(F,len,1);
NTT(G,len,1);
for(int re i=0;i<len;++i)F[i]=mul(F[i],G[i]);
NTT(F,len,-1);
reverse(F,F+N+1);
int ans=0;
for(int re i=0;i<=N;++i)ans=add(ans,mul(w[i],mul(F[i],ifac[i])));
cout<<ans<<'\n';
return 0;
}