#排列組合,揹包#CF232B Table
阿新 • • 發佈:2022-03-01
排列組合,揹包
題目
有一個 \(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; }