HDU 5794
给你一个边界h,w;
有n个障碍物,有障碍物的地方不能走。马走日字,问左上到右下有多少种路径。
做法:dp[i]表示不走过其他点的到这个点的路径数。
所以转移方程就有,这个点的值等于全部路径,减去,在它之前的所有障碍点到这个点的路径。因为对于每一个障碍点,都是第一次到达障碍点,所以后面只要计算全部路径,就一定可以不重不漏。
这道题可能在h,w的地方有个障碍,坑爹呢。。。
#include <cstdio> #include <cstring> #include <vector> #include <cmath> #include <stack> #include <cstdlib> #include <queue> #include <map> #include <iostream> #include <algorithm> #include <bits/stdc++.h> using namespace std; typedef long long LL; const long long MOD=110119; LL all[MOD+5],f[MOD+5]; LL C(LL n, LL m) { if(m > n) return 0; if (m==0) return 1; if (m<0) return 0; return f[n]*all[f[m]]%MOD*all[f[n-m]]%MOD; } LL Lucas(LL n, LL m) { if(m == 0) return 1; return C(n % MOD, m % MOD) * Lucas(n / MOD, m / MOD) % MOD; } void init() { f[1]=f[0]=all[1]=1; for(int i=2; i<=MOD; ++i) { f[i]=f[i-1]*i%MOD; all[i]=all[MOD%i]*(MOD-MOD/i)%MOD; } } LL dp[2010]; struct node { LL x,y; } point[2010]; LL cmp(node a,node b) { return a.x<b.x; } int main() { init(); LL h,w,n,ncas=1; // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); while (scanf ("%I64d%I64d%I64d",&h,&w,&n)!=EOF) { int flag=0; memset(dp,0,sizeof(dp)); LL t1,t2; for (int i=0; i<n; ++i) { scanf ("%I64d%I64d",&t1,&t2); if (t1==h&&t2==w) flag=1; point[i].x=t1-1; point[i].y=t2-1; } sort(point,point+n,cmp); point[n].x=h-1; point[n].y=w-1; ++n; if ((point[n-1].x+point[n-1].y)%3!=0||flag) { printf ("Case #%I64d: %I64d\n",ncas++,0); continue; } for (int i=0; i<n; i++) { if ((point[i].x+point[i].y)%3==0) { LL di=(point[i].x+point[i].y)/3; LL gao=min(point[i].x,point[i].y)-di; dp[i]=Lucas(di,gao); for (int j=0;j<i;j++) { if (point[j].y<point[i].y&&point[j].x<point[i].x) { LL xx=point[i].x-point[j].x,yy=point[i].y-point[j].y; if ((xx+yy)%3==0) { LL dd=(xx+yy)/3; LL gg=min(xx,yy)-dd; dp[i]-=(Lucas(dd,gg)*dp[j])%MOD; dp[i]=(dp[i]+MOD)%MOD; } } } } } printf ("Case #%I64d: %I64d\n",ncas++,dp[n-1]); } return 0; }