要求\(k\)种颜色恰好出现\(S\)次
也就是出现\(S\)次的颜色恰好有\(k\)种
我们可以发现\(lim=max\{k\}=min(\frac{n}{s},{m})\)
我们可以容斥一下 就是
出现\(S\)次的颜色至少存在\(k\)种
那么
\[dp[k]=C_m^kC_{n}^{ks}(m-k)^{m-ks}\]
应该和好理解的
出现\(S\)次的颜色恰好\(k\)种就是
\[ans[k]=\sum_{j=k}^{lim}(-1)^{j-k}C_j^kdp[j]\]
\(j\)种颜色中\(k\)种被重复算了\(C_j^k\)次
那么我们拆开就是
\[ans[k]* k!=\sum_{j=k}^{lim}\frac{(-1)^{j-k}}{(j-k)!}dp[j]* j!\]
如何求\(\sum_{j=k}^{lim}\frac{(-1)^{j-k}}{(j-k)!}dp[j]* j!\)
我们考虑维护出
\[a[i]=dp[i]* i!\ \ \ \ \ \ b[i]=\frac{(-1)^{i}}{i!}\]
然后就是套路 翻转\(a\)序列
那么就是多项式乘法\(NTT\)了
那么对应就是\(lim-j+j-k=lim-k\)
所以我们再反转一下就可以了
然后累加就可以了
/*-------------OI使我快乐-------------*/
int n,m,s,have,lim,all;
ll ans;
ll fav[M],fac[M],inv[M],num[M];
ll dp[M],cdy[M],wzy[M];
int key[M];
IL ll C(int x,int y)
{return fac[x]*fav[x-y]%mod*fav[y]%mod;}
IL ll qpow(ll x,ll y)
{ll res=1;for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod;return res;}
IL void NTT(ll *A,int knd)
{
for(R int i=0;i<lim;++i) if(i<key[i]) swap(A[i],A[key[i]]);
for(R int mid=1;mid<lim;mid<<=1)
{
ll Wn=qpow(knd==1 ? 3:Gi,(mod-1)/(mid<<1));
for(R int j=0;j<lim;j+=(mid<<1))
{
ll w=1;
for(R int k=0;k<mid;++k,w=w*Wn%mod)
{
ll x=A[j+k],y=w*A[j+k+mid]%mod;
A[j+k]=(x+y)%mod;A[j+k+mid]=(x-y+mod)%mod;
}
}
}
if(knd==-1)
{
ll inv=qpow(lim,mod-2);
for(R int i=0;i<lim;++i) A[i]=A[i]*inv%mod;
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n);read(m);read(s);have=min(n/s,m);
for(R int i=0;i<=m;++i) read(num[i]),num[i]%=mod;
fac[0]=fac[1]=fav[0]=fav[1]=inv[0]=inv[1]=1;
for(R int i=2;i<=10000000;++i)
{
fac[i]=fac[i-1]*i%mod;
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
fav[i]=fav[i-1]*inv[i]%mod;
}
// for(R ll i=1;i<=10;++i) printf("%lld%c",fac[i],(i==10 ? '\n':' '));
for(R int i=0;i<=have;++i)
dp[i]=C(m,i)*C(n,i*s)%mod*fac[i*s]%mod*qpow(fav[s],i)%mod*qpow(m-i,n-i*s)%mod;
// for(R ll i=0;i<=have;++i)
// printf("%lld%c",dp[i],(i==have ? '\n':' '));
for(R int i=0;i<=have;++i)
{
cdy[i]=(((i&1) ? -1:1)*fav[i]%mod+mod)%mod;
wzy[i]=dp[i]*fac[i]%mod;
}
reverse(wzy,wzy+have+1);
for(lim=1;lim<=(have<<1);lim<<=1) ++all;
for(R int i=0;i<lim;++i) key[i]=((key[i>>1]>>1)|((i&1)<<(all-1)));
NTT(cdy,1);NTT(wzy,1);
for(R int i=0;i<lim;++i) cdy[i]=cdy[i]*wzy[i]%mod;
NTT(cdy,-1);
reverse(cdy,cdy+have+1);
for(R int i=0;i<=have;++i) ans=(ans+num[i]*cdy[i]%mod*fav[i]%mod)%mod;
printf("%lld\n",(ans%mod+mod)%mod);
// fclose(stdin);
// fclose(stdout);
return 0;
}
原文:https://www.cnblogs.com/LovToLZX/p/10590450.html