[CF559C] Gerald and Giant Chess - 计数dp
作者:互联网
Description
给定一个 \(H \times W\) 的棋盘,有 \(N\) 个障碍格子,棋子每次可以向右或者向下移动一步,求从左上角到右下角有多少种不同的路线。\(N \le 2000\)
Solution
由于 \(N\) 较小,考虑 dp,设 \(f[i]\) 表示走到第 \(i\) 个障碍点(且之前不经过其它任何障碍点)的方案数,则
\[f[i]=g(x_i,y_i) - \sum_{j \to i} g(x_i-x_j+1,y_i-y_j+1 )\cdot f[j] \]
其中 \(j \to i \Leftrightarrow x_j \le x_i \and y_j \le y_i\),\(g(x,y)\) 表示无障碍情况下 \((1,1) \to (x,y)\) 的方案数,有
\[g(x,y)=\binom {x+y-2}{x-1} \]
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2005;
const int M = 200005;
const int mod = 1e9+7;
int f[N],frac[M],ifrac[M],h,w,x[N],y[N],n;
struct pii
{
int x,y;
bool operator < (const pii &obj)
{
if(x==obj.x) return y<obj.y;
return x<obj.x;
}
} buf[N];
int qpow(int p,int q)
{
return (q&1 ? p : 1) * (q ? qpow(p*p%mod,q>>1) : 1) % mod;
}
int inv(int p)
{
return qpow(p,mod-2);
}
int nCr(int n,int m)
{
return frac[n]*ifrac[m]%mod*ifrac[n-m]%mod;
}
int g(int x,int y)
{
return nCr(x+y-2,x-1);
}
signed main()
{
ios::sync_with_stdio(false);
cin>>h>>w>>n;
for(int i=1;i<=n;i++) cin>>x[i]>>y[i];
frac[0]=ifrac[0]=1;
for(int i=1;i<M;i++) frac[i]=frac[i-1]*i%mod;
for(int i=1;i<M;i++) ifrac[i]=inv(frac[i]);
for(int i=1;i<=n;i++) buf[i].x=x[i], buf[i].y=y[i];
sort(buf+1,buf+n+1);
for(int i=1;i<=n;i++) x[i]=buf[i].x, y[i]=buf[i].y;
f[0]=1;
x[0]=y[0]=1;
x[n+1]=h;
y[n+1]=w;
for(int i=1;i<=n+1;i++)
{
f[i]=g(x[i],y[i]);
for(int j=1;j<i;j++)
{
if(x[i]>=x[j] && y[i]>=y[j]) f[i]-=g(x[i]-x[j]+1,y[i]-y[j]+1)*f[j];
f[i]%=mod;
f[i]+=mod;
f[i]%=mod;
}
}
cout<<f[n+1]<<endl;
}
标签:Giant,le,return,int,Gerald,ifrac,CF559C,const,mod 来源: https://www.cnblogs.com/mollnn/p/13589059.html