codeforces 559C Gerald and Giant Chess (dp+乘法逆元)

题目链接:

http://codeforces.com/contest/559/problem/C

 

题目大意:

h*w的棋盘,其中有n个格子不可以走,求从左上角走到右下角有多少种方案(模1e9+7),只能向右或向下走

1 ≤ h, w ≤ 10^5, 1 ≤ n ≤ 2000

 

Solution:

对所有点排序

考虑dp,dp[i]表示从左上角合法地走到第i个点共有dp[i]个方案,显然第i个点与左上角之间没有其他点时有C(x+y-2,x-1)种方案,而如果有其他点时则要减去部分

即 dp[i] = C(x+y-2,x-1) - sum{dp[j] * C(i.x - j.x + i.y - j.y, i.x - j.x) | j < i}

 

还有个问题是计算组合数时做除法,因为要取模,所以这里只能乘上除数关于模数的逆元素

求乘法逆元几种方法 a * a' ≡ 1 (mod p)

  扩展欧几里得
    计算 a“ * a + k * p = 1 中的系数a”和k,求出来a“可能为负数,注意加p或者取模,可以得到a'

  费马小定理: 当p是质数,且Gcd(a,p)=1,那么 a^(p-1) ≡ 1 (mod p)
    显然a' = a^(p-2)时,有a * a' ≡ 1 (mod p)

  (欧拉函数 略)

 

实现时用的费马小定理

  1 //#define __LOCAL
  2 #define __LLD
  3 
  4 #include <stdio.h>
  5 #include <stdlib.h>
  6 #include <string.h>
  7 #include <math.h>
  8 #include <time.h>
  9 #include <algorithm>
 10 #include <queue>
 11 #include <vector>
 12 #include <stack>
 13 #include <set>
 14 #include <map>
 15 #include <iostream>
 16 using namespace std;
 17 typedef long long LL;
 18 typedef pair<int,int> PII;
 19 const int ninf = 0x80000000;
 20 const int inf = 0x7FFFFFFF;
 21 const LL INF = (LL)inf*inf;
 22 
 23 #ifdef __LLD
 24     #define printLLln(x) printf("%lld\n", x)
 25     #define printLL(x) printf("%lld", x)
 26 #else
 27     #define printLLln(x) printf("%I64d\n", x)
 28     #define printLL(x) printf("%I64d", x)
 29 #endif
 30 
 31 #define MP make_pair
 32 #define PB push_back
 33 //
 34 
 35 const int MAXN = 2010;
 36 const int mod = 1e9+7;
 37 const int mm = 2e5+10;
 38 int n, h, w;
 39 vector<PII> po;
 40 int dp[MAXN];
 41 int fact[mm],ifact[mm];
 42 
 43 void init()
 44 {
 45     memset(dp, 0, sizeof(dp));
 46     po.clear();
 47 }
 48 int qpow(int x, int n)
 49 {
 50     int res=1;
 51     while(n){
 52         if(n&1)
 53             res = ((LL)res * x) % mod;
 54         x = ((LL)x*x)%mod;
 55         n >>= 1;
 56     }
 57     return res;
 58 }
 59 void factorial()
 60 {
 61     memset(fact, 0, sizeof fact);
 62     memset(ifact, 0, sizeof ifact);
 63     fact[0] = ifact[0] = 1;
 64     for(int i=1;i<mm;++i)
 65     {
 66         fact[i] = ((LL)fact[i-1] * i) % mod;
 67         ifact[i] = qpow(fact[i], mod-2);
 68     }
 69 }
 70 int C(int x, int y)
 71 {
 72     if(x<y || x<0 || y<0)return 0;
 73     return (LL)fact[x]*(((LL)ifact[x-y]*ifact[y])%mod)%mod;
 74 }
 75 void solve()
 76 {
 77     int x,y;
 78     for(int i=0;i<n;++i)
 79     {
 80         scanf("%d%d",&x,&y);
 81         po.PB(MP(x,y));
 82     }
 83     po.PB(MP(1,1));
 84     po.PB(MP(h,w));
 85     sort(po.begin(), po.end());
 86     for(int i=0;i<po.size();++i)
 87     {
 88         dp[i] = C(po[i].first+po[i].second-2, po[i].first-1);
 89         for(int j=1;j<i;++j)
 90         {
 91             dp[i] -= (LL)dp[j]*C(po[i].first-po[j].first+po[i].second-po[j].second, po[i].first-po[j].first)%mod;
 92             while(dp[i] < 0)
 93                 dp[i] += mod;
 94         }
 95 //        printf("%d\n", dp[i]);
 96     }
 97     printf("%d\n", dp[n+1]);
 98 }
 99 int main()
100 {
101 #ifdef __LOCAL
102     printf("OK\n");
103     freopen("data.in", "r", stdin);
104 //    freopen("data.out", "w", stdout);
105 #endif
106     factorial();
107     while(scanf("%d%d%d",&h, &w, &n)!=EOF){
108         init();
109         solve();
110     }
111 
112     return 0;
113 }
View Code

 

参考:

http://blog.csdn.net/baoli1008/article/details/47037221

posted @ 2015-07-27 19:57  可乐君  阅读(533)  评论(0编辑  收藏  举报