HDU 5794 A Simple Chess Lucas定理+dp
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794
题意概述:
给出一个N*M的网格。网格上有一些点是障碍,不能经过。行走的方式是向右下角跳马步。求有多少种方案可以从(1,1)走到(N,M)。
多组数据,组数不超过25。N,M<=1e18。
分析:
还是水题。。。(我写这个的原因只是因为我第一次用lucas)分析一下可以发现横跳和纵跳各自的步数是确定的,所以变成了一个组合数问题。
当有障碍的时候按照第一次碰到的障碍分类,先把棋盘当成完全没有障碍,然后扣掉这些方案即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<set> 9 #include<map> 10 #include<vector> 11 #include<cctype> 12 using namespace std; 13 const int mo=110119; 14 typedef long long LL; 15 16 LL N,M,R; 17 int inv[mo],J[mo],Ji[mo]; 18 struct XY{ 19 LL x,y; 20 friend bool operator < (XY a,XY b){ 21 return a.x<b.x||a.x==b.x&&a.y<b.y; 22 } 23 friend bool operator == (XY a,XY b){ 24 return a.x==b.x&&a.y==b.y; 25 } 26 }p[105]; 27 int f[105]; 28 29 int Lucas(LL x,LL y) 30 { 31 if(x<y) return 0; 32 if(x<mo&&y<mo) return 1ll*J[x]*Ji[x-y]%mo*Ji[y]%mo; 33 return 1ll*Lucas(x/mo,y/mo)*Lucas(x%mo,y%mo)%mo; 34 } 35 void ready() 36 { 37 inv[1]=1; 38 for(int i=2;i<mo;i++) 39 inv[i]=1ll*inv[mo%i]*(mo-mo/i)%mo; 40 J[0]=1,Ji[0]=1; 41 for(int i=1;i<mo;i++){ 42 J[i]=1ll*J[i-1]*i%mo; 43 Ji[i]=1ll*Ji[i-1]*inv[i]%mo; 44 } 45 } 46 int solve(LL n,LL m) 47 { 48 if((2*n-m-1)<0||(2*n-m-1)%3||(2*m-n-1)<0||(2*m-n-1)%3) return 0; 49 LL a=(2*m-n-1)/3,b=(2*n-m-1)/3; 50 return Lucas(a+b,b); 51 } 52 int main() 53 { 54 ready(); 55 int T=0; 56 while(cin>>N>>M>>R){ 57 int ans=solve(N,M); 58 if(R){ 59 for(int i=1;i<=R;i++) 60 cin>>p[i].x>>p[i].y; 61 sort(p+1,p+R+1); 62 R=unique(p+1,p+R+1)-p-1; 63 memset(f,0,sizeof(f)); 64 for(int i=1;i<=R;i++){ 65 f[i]=solve(p[i].x,p[i].y); 66 for(int j=1;j<i;j++)if(p[j].x<p[i].x&&p[j].y<p[i].y) 67 f[i]=(f[i]-1ll*f[j]*solve(p[i].x-p[j].x+1,p[i].y-p[j].y+1)%mo+mo)%mo; 68 } 69 for(int i=1;i<=R;i++) 70 ans=(ans-1ll*f[i]*solve(N-p[i].x+1,M-p[i].y+1)%mo+mo)%mo; 71 } 72 cout<<"Case #"<<++T<<": "<<ans<<'\n'; 73 } 74 return 0; 75 }