AT_tenka1_2014_final_a 解题报告
前言:
怎么没有人发题解?我发一篇。玩了7天人废了,写了好久找不对初始状态。
思路
f[i][j]表示考虑第i种数字(0~h-1),已经有 j 个位置被确定了,现在用到 i 的方案数。
注意到 \(0\) 和别的数字有区别,作为初始状态,详见代码。状态转移方程详见代码。预处理阶乘逆元和阶乘就不讲了,大家都会。写这种简单dp的时候注意明确状态含义哦。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
using ll=long long;
const int maxn=2400,mod=1e9+7;
int n,h,w;
int fac[maxn+10],inv[maxn+10];
int f[maxn+10][maxn+10];//f[i][j]考虑第i种数字(0~h-1),已经有 j 个位置被确定了,现在用到 i 的方案数
ll qp(ll a,int b){
ll res=1;
while(b){
if(b&1)res=1ll*res*a%mod;
a=1ll*a*a%mod;
b>>=1;
}return res;
}
ll C(int N,int M){
if(M==0)return 1;
if(N<M||N==0)return 0;
return fac[N]*inv[M]%mod*inv[N-M]%mod;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>h>>n>>w;
fac[0]=1;
for(int i=1;i<=maxn;++i)fac[i]=fac[i-1]*i%mod;
inv[maxn]=qp(fac[maxn],mod-2);
for(int i=maxn-1;i>=0;--i)inv[i]=inv[i+1]*(i+1)%mod;
f[0][0]=1;
for(int j=1;j<=n;++j)
f[0][j]=C(w-1,j);
for(int i=1;i<h;++i)
for(int j=0;j<=w;++j)
for(int k=0;k<=n&&j+k<=w;++k)
(f[i][j+k]+=f[i-1][j]*C(w-j,k)%mod)%=mod;
for(int i=0;i<h;++i)for(int j=0;j<=w;++j)cerr<<f[i][j]<<" \n"[j==w];
cout<<f[h-1][w]<<"\n";
return 0;
}

浙公网安备 33010602011771号