标签:long spl ret amp 就会 fine put i+1 define
题目链接:Click here
我们把问题转化一下,改成可以放白球和其他颜色的球
那么对于一种合法的方案,显然有它的任意一个前缀的白球数大于等于其他颜色数
那么,我们考虑设\(f[i][j]\)表示已经放了\(i\)个白球,刚好放完了\(j\)种颜色的方案数
考虑有两种转移,一种是我们再放一个白球,或者再加入一种颜色
这里我们钦定接下来放的第一个球一定在第一个空缺的位置,否则就会算重
那么转移就是这样的:
\[
f[i][j]=f[i-1][j]+f[i][j-1]\times {(k-1)\times (n-j+1)+n-i-1 \choose k-2}
\]
需要注意的是,当\(k=1\)时,我们需要给出特判,并且我们在\(dp\)时是没有考虑颜色的排列顺序的,所以最后要乘上阶乘
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e3+11;
const int M=4e6+11;
const int mod=1e9+7;
int n,k,f[N][N],fac[M],ifac[M];
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int qpow(int a,int b){
int re=1;
while(b){
if(b&1) re=(re*a)%mod;
b>>=1;a=a*a%mod;
}return re;
}
int C(int a,int b){
if(a<b) return 0;
return fac[a]*ifac[b]%mod*ifac[a-b]%mod;
}
signed main(){
n=read(),k=read();
if(k==1) return puts("1"),0;
fac[0]=1;ifac[0]=1;f[0][0]=1;
for(int i=1;i<=n*k;i++) fac[i]=fac[i-1]*i%mod;
ifac[n*k]=qpow(fac[n*k],mod-2);
for(int i=n*k-1;i;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
for(int i=1;i<=n;i++)
for(int j=0;j<=i;j++){
if(i>j) f[i][j]+=f[i-1][j];
f[i][j]=(f[i][j]+f[i][j-1]*C((n-j+1)*(k-1)+n-i-1,k-2)%mod)%mod;
}
printf("%lld\n",f[n][n]*fac[n]%mod);
return 0;
}
标签:long spl ret amp 就会 fine put i+1 define
原文地址:https://www.cnblogs.com/NLDQY/p/12214807.html