1. 程式人生 > 其它 >#排列組合,揹包#CF232B Table

#排列組合,揹包#CF232B Table

排列組合,揹包

題目

有一個 \(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;
}