LOJ #2833. 「JOISC 2018 Day 1」帐篷 动态规划
这种问题设最裸的状态就好了.
令 $f[i][j]$ 表示 $i \times j$ 矩阵的答案.
然后直接转移就行了.
code:
#include <bits/stdc++.h> #define N 3004 #define ll long long #define mod 1000000007 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int fac[N],inv[N],po[N*N],dp[N][N]; int qpow(int x,int y) { int tmp=1; for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod; return tmp; } int INV(int x) { return qpow(x,mod-2); } int C(int x,int y) { if(x<y||x<0||y<0) return 0; return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod; } void init() { fac[0]=inv[0]=po[0]=1; for(int i=1;i<N;++i) { fac[i]=(ll)fac[i-1]*i%mod; inv[i]=INV(fac[i]); } for(int i=1;i<N*N;++i) po[i]=(ll)po[i-1]*4%mod; } int main() { // setIO("input"); int i,j,n,m,ans=0; init(); scanf("%d%d",&n,&m); for(i=0;i<=n;++i) dp[i][0]=1; for(i=0;i<=m;++i) dp[0][i]=1; dp[0][0]=1; // 前 i 行,占用了 j 列 for(i=1;i<=n;++i) { for(j=1;j<=m;++j) { dp[i][j]+=dp[i][j-1]; (dp[i][j]+=(ll)dp[i-1][j-1]*4%mod*i%mod)%=mod; if(i>=2) (dp[i][j]+=(ll)dp[i-2][j-1]*C(i,2)%mod)%=mod; if(j>=2) (dp[i][j]+=(ll)dp[i-1][j-2]*i%mod*(j-1)%mod)%=mod; } } printf("%d\n",dp[n][m]-1); return 0; }