有一个 \(n\times m\) 的矩阵,求使得每个 \(n\times n\) 的矩阵中都有正好 \(k\) 个点的方案数。
考虑到如果确定了前 \(n\) 列的选点个数,那么对于一列选点的个数是固定的,可以用组合数实现。
那么设 \(dp[i][j]\) 表示前 \(i\) 列选择了 \(j\) 个点的方案数。
\(dp[i][j]=\sum_{k=1}^ndp[i-1][j-k]*C(n,k)^{\frac{m}{n}}\)
向上取整向下取整取决于 \(i\),然后组合数快速幂都预处理就可以做到 \(O(n^4)\) 了
#include <iostream> using namespace std; const int N=111,mod=1000000007; long long m; int n,k,inv[N],s,f[N*N],g[N],G[N],dp[N*N]; int ksm(int x,int y){ int ans=1; for (;y;y>>=1,x=1ll*x*x%mod) if (y&1) ans=1ll*ans*x%mod; return ans; } void Mo(int &x,int y){x=x+y>=mod?x+y-mod:x+y;} int main(){ cin>>n>>m>>k,inv[0]=inv[1]=s=1; for (int i=2;i<=n;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod; for (int i=2;i<=n;++i) inv[i]=1ll*inv[i-1]*inv[i]%mod,s=1ll*s*i%mod; for (int i=0;i<=n;++i) f[i]=1ll*s*inv[i]%mod*inv[n-i]%mod; for (int i=0;i<=n;++i) g[i]=ksm(f[i],(m/n)%(mod-1)),G[i]=1ll*g[i]*f[i]%mod; dp[0]=1; for (int T=0;T<m%n;++T){ for (int j=0;j<=k;++j) f[j]=dp[j]; for (int i=1;i<=n;++i) for (int j=i;j<=k;++j) Mo(dp[j],1ll*f[j-i]*G[i]%mod); } for (int T=m%n;T<n;++T){ for (int j=0;j<=k;++j) f[j]=dp[j]; for (int i=1;i<=n;++i) for (int j=i;j<=k;++j) Mo(dp[j],1ll*f[j-i]*g[i]%mod); } cout<<dp[k]; return 0; }