http://codeforces.com/problemset/problem/559/C
题目大意:给出一个棋盘为h*w,现在要从(1,1)到(h,w),只能向右或向下走,其中有n个黑点不能走,问有多少种方案(模10^9+7)可以从左上角走到右下角(1,1和h,w永远是可以走的)
思路:用dp,首先把终点也算入黑点,然后dp这样:
f[i]=从起点到这个点的所有路径数
f[i]-f[j]*从j点到i点的所有路径数
为什么这样?因为我们先算出总的路径数,再去掉不合法的路径数,也就是:从经过第一个黑点开始到达当前点的所有法案数都是不合法的。还要记得把点排序一下,然后输出终点的dp值就是答案,还要记得预处理一下组合数。
PS:组合数预处理要到20W,因为题目的n,m范围是10W,但是xy相加就会达到20W了
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 #include<iostream> 6 #define ll long long 7 const ll Mod=1000000007; 8 struct node{ 9 int x,y; 10 }p[200009]; 11 ll jcny[200009],jc[200009],f[200009]; 12 int n,m,K; 13 int read(){ 14 int t=0,f=1;char ch=getchar(); 15 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 16 while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} 17 return t*f; 18 } 19 void exgcd(ll a,ll b,ll &x,ll &y){ 20 if (b==0){ 21 x=1; 22 y=0; 23 return; 24 } 25 exgcd(b,a%b,x,y); 26 ll t=x; 27 x=y; 28 y=t-(a/b)*y; 29 } 30 void init(){ 31 jc[0]=jcny[0]=1; 32 for (int i=1;i<=200005;i++) jc[i]=(jc[i-1]*i)%Mod; 33 ll x,y; 34 exgcd(jc[200005],Mod,x,y); 35 jcny[200005]=(x%Mod+Mod)%Mod; 36 for (int i=200004;i>=1;i--) 37 jcny[i]=(jcny[i+1]*(i+1))%Mod; 38 } 39 bool cmp(node a,node b){ 40 return a.x+a.y<b.y+b.x; 41 } 42 ll C(int n,int m){ 43 return ((jc[n]*jcny[m]%Mod)*jcny[n-m])%Mod; 44 } 45 int main(){ 46 n=read();m=read();K=read(); 47 for (int i=1;i<=K;i++){ 48 p[i].x=read();p[i].y=read(); 49 } 50 K++; 51 p[K].x=n; 52 p[K].y=m; 53 std::sort(p+1,p+1+K,cmp); 54 init(); 55 for (int i=1;i<=K;i++){ 56 ll res=C(p[i].x+p[i].y-2,p[i].x-1); 57 for (int j=1;j<=K;j++) 58 if (j!=i&&p[j].x<=p[i].x&&p[j].y<=p[i].y) 59 res=((res-(f[j]*C(p[i].x-p[j].x+1+p[i].y-p[j].y+1-2,p[i].x-p[j].x+1-1))%Mod)%Mod+Mod)%Mod; 60 f[i]=res; 61 } 62 printf("%I64d ",f[K]); 63 return 0; 64 }