【組合數學】【DP】三校聯考 10.15 —— Chess
阿新 • • 發佈:2018-12-15
題目描述
dirty 在一個棋盤上放起了棋子。
棋盤規格為 n ∗ m,他希望任意一個 n ∗ n 的區域內都有 K 個棋子。dirty 很快就放置好了一
個滿足條件的棋盤方案,但是他認為這樣過於簡單了,他希望知道有多少個滿足條件的方案。
看題第一眼即可知道是關於組合數學的.
通過觀察發現,如果棋盤上前n列已經定了,那麼之後的情況只會是前面n列的迴圈.因此只需考慮n列.
可以得出以下式子
其中
這個的含義是在每一列的棋子數固定的情況下前n列的方案數.
那麼這種情況對於答案的貢獻為
然後將所有的情況利用dp統計.(詳見程式碼)
題目時間限制比較卡,注意預處理出組合數.
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MOD=1e9+7;
const int MAXN=105;
const int MAXM=10005;
int n,c;
ll m,x1,x2;
ll fac[MAXM],finv[MAXM];
ll d[MAXN][MAXM],f[2][MAXN];
void Init(){
fac[0]=1;
for(int i=1;i<MAXM;i++) fac[i]=fac[i- 1]*i%MOD;
finv[1]=1;
for(int i=2;i<MAXM;i++) finv[i]=(MOD-MOD/i)*finv[MOD%i]%MOD;
finv[0]=1;
for(int i=1;i<MAXM;i++) finv[i]=finv[i-1]*finv[i]%MOD;
}
ll C(ll x,ll y){
if(x<y) return 0;
return (fac[x]*finv[y]%MOD)*finv[x-y]%MOD;
}
ll ksm(ll x,ll y){
y%=(MOD-1);
ll res=1;
while(y){
if(y&1) res=res*x%MOD;
x=x*x%MOD;
y>>=1ll;
}
return res;
}
int main(){
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
Init();
scanf("%d %lld %d",&n,&m,&c);
if(m<n) return printf("%lld",ksm(2,n*m)),0;
x1=m/n,x2=m%n;
d[n+1][0]=1;
for(int i=0;i<=n;i++) f[0][i]=ksm(C(n,i),x1),f[1][i]=ksm(C(n,i),x1+1);
for(int i=n;i>=1;i--)
for(int j=c;j>=0;j--){
for(int k=0;k<=min(n,j);k++)
d[i][j]=(d[i][j]+d[i+1][j-k]*(i<=x2?f[1][k]:f[0][k])%MOD)%MOD;
if(i==1) break;
}
printf("%lld\n",d[1][c]);
fclose(stdin);
fclose(stdout);
}