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)
(欧拉函数 略)
实现时用的费马小定理
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
参考: