网上找了很多人的博客,都看不太懂,还是大力学长的方法好。
要说明的一点是,因为是比较大的数字的组合数再加上mod比较小,因此用Lucas定理求组合数。
代码如下(有注释):
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <set> 5 #include <vector> 6 using namespace std; 7 const int mod = 110119; 8 typedef long long ll; 9 typedef pair<ll,ll> pii; 10 11 int k; 12 ll fact[120000+5],dp[100+5]; 13 ll n,m; 14 vector<pii> V; 15 16 void init() 17 { 18 fact[0] = fact[1] = 1; 19 for(int i=2;i<=120000;i++) fact[i] = fact[i-1] * i % mod; 20 } 21 22 void ex_gcd(ll a,ll b,ll &x,ll &y,ll &d) 23 { 24 if(!b) {d = a; x = 1; y = 0;} 25 else 26 { 27 ex_gcd(b,a%b,y,x,d); 28 y -= x * (a/b); 29 } 30 } 31 32 ll qpow(ll a,ll b) 33 { 34 ll ans = 1; 35 while(b) 36 { 37 if(b & 1) ans = ans * a % mod; 38 a = a * a % mod; 39 b >>= 1; 40 } 41 return ans; 42 } 43 44 ll inv(ll t,ll p) 45 { 46 /*ll x,y,d; 47 ex_gcd(t,p,x,y,d); 48 return d==1 ? (x%mod+mod)%mod : -1;*/ 49 return qpow(t,p-2); 50 } 51 52 int comb(int n,int m) 53 { 54 if(m<0 || n<m) return 0; 55 return fact[n] * 1LL * inv(fact[m],mod) % mod * inv(fact[n-m],mod) % mod; 56 } 57 58 ll Lucas(ll n,ll m,int p) 59 { 60 return m ? Lucas(n/p,m/p,p) * comb(n%p,m%p) % mod : 1; 61 } 62 63 ll solve(int i,int j) // j to i 的无视障碍的步数总数 64 { 65 if(V[i].second < V[j].second || V[i].first < V[i].first || (V[i].first+V[i].second-V[j].first-V[j].second)%3) return -1; 66 ll need = (V[i].first+V[i].second-V[j].first-V[j].second) / 3; 67 // need 表示走过的步数 68 ll step = Lucas(need, V[i].first-V[j].first-need, mod); 69 // 第二个参数表示走过的两步的步数 70 // 总的步数(need)中选择若干步是走两步的 71 return step % mod; 72 } 73 74 int main() 75 { 76 init(); 77 int kase = 1; 78 while(scanf("%I64d%I64d%d",&n,&m,&k)==3) 79 { 80 V.clear(); 81 for(int i=1;i<=k;i++) 82 { 83 ll x,y;scanf("%I64d%I64d",&x,&y); 84 V.push_back(pii(x,y)); 85 } 86 V.push_back(pii(1,1)); 87 V.push_back(pii(n,m)); 88 sort(V.begin(),V.end()); 89 memset(dp,0,sizeof(dp)); 90 int sz = V.size(); 91 for(int i=1;i<sz;i++) 92 { 93 dp[i] = solve(i,0); 94 if(dp[i] == -1) dp[i] = 0; 95 for(int j=0;j<i;j++) 96 { 97 ll step = solve(i,j); 98 if(step != -1) 99 { 100 dp[i] -= step * dp[j] % mod; 101 // 所有从原点到i这个点的路径中,从原点到禁止点再从该禁止点到i点的所有路径都是不被允许的,需要减掉 102 if(dp[i] < 0) dp[i] = ((dp[i] % mod) + mod) % mod; 103 } 104 } 105 } 106 printf("Case #%d: %I64d ",kase++,dp[sz-1]); 107 } 108 }