思路:dp+组合数
依题可得第1列与第n+1列,第2列与第n+2列...第x列与第x%n列所放的棋子数目相同,可以先处理出每一列放的棋子的方法数
f[i][j]表示前i列放j个棋子的方法数,我们只需要考虑前n列,因为第n+1列与第1列相同。具体看代码。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=110,mod=1e9+7;
typedef long long LL;
LL f[N][N*N],c[N][N],g[N][2];
LL n,m,k;
LL qmi(LL a,LL k)
{
LL res=1;
while(k)
{
if(k&1) res=res*a%mod;
a=a*a%mod;
k>>=1;
}
return res;
}
void init()
{
for(LL i=0;i<N;i++)
{
for(LL j=0;j<=i;j++)
{
if(!j) c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
}
int main()
{
init();//组合数模板
cin>>n>>m>>k;
LL d=m/n,y=m%n;//每n列循环一次,列号小于y的循环d+1次,列号大于y的,循环d次
for(LL i=0;i<=min(k,n);i++)
{
g[i][0]=qmi(c[n][i],d);//一列放i个棋子循环d次的方案数
g[i][1]=qmi(c[n][i],d+1);//一列放i个棋子循环d+1次的方案数
}
f[0][0]=1;//初始化,前0列放0个的方案数是1
for(LL i=1;i<=n;i++)
{
for(LL j=0;j<=k;j++)
{
for(LL h=0;h<=min(j,n);h++)
f[i][j]=(f[i][j]+f[i-1][j-h]*g[h][i<=y]%mod)%mod;//遍历第i列放的棋子数
}
}
cout<<f[n][k]<<endl;
return 0;
}