C/C++教程

#排列组合,背包#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;
}
这篇关于#排列组合,背包#CF232B Table的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!