首页 > 技术文章 > 2016-5-22 百度之星第三题--瞬间移动

wen-ge 2016-05-22 19:45 原文

http://acm.hdu.edu.cn/showproblem.php?pid=5698

刚开始计算了下,就是当前位置等于其左边的值加上上边的值,于是写了个二维数组,dp[2][100005],进行存储,然后复杂度为o(n*m),超时了

于是,杨神牛,提醒了我说杨辉三角,然后,写了个组合数取模,但当组合数比较大时,计算的组合数取模不对

百度了下大组合数取模,然后,知道转化为阶乘来算,用上LUCAS定理,乘法逆元,快速幂

LUCAS定理: Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p) 

乘法逆元:

 (a/b)%mod ,其实如果mod是质数的时候可以用费马小定理来做,即

a*b^(mod-2)//这个比较常用

 1 #include <cmath>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <memory>
 7 #include <string>
 8 #include <queue>
 9 #include <map>
10 #include <stdio.h>
11 #include <vector>
12 #include <stack>
13 #include <fstream>
14 #include <set>
15 #define N 200005
16 #define mod 1000000007
17 using namespace std;
18 long long mod_pow(int a,int n,int p)
19 {
20     long long ret=1;
21     long long A=a;
22     while(n)
23     {
24         if (n & 1)
25             ret=(ret*A)%p;
26         A=(A*A)%p;
27         n>>=1;
28     }
29     return ret;
30 }
31 
32 long long factorial[N];
33 
34 void init()
35 {
36     factorial[0] = 1;
37     for(int i = 1;i <= N;i++)
38         factorial[i] = factorial[i-1]*i%mod;
39 }
40 
41 long long Lucas(long long a,long long k,long long p) //求C(n,m)%p p最大为10^5。a,b可以很大!
42 {
43     long long re = 1;
44     while(a && k)
45     {
46         long long aa = a%p;long long bb = k%p;
47         if(aa < bb) return 0;
48         re = re*factorial[aa]*mod_pow(factorial[bb]*factorial[aa-bb]%p,p-2,p)%p;
49         a /= p;
50         k /= p;
51     }
52     return re;
53 }
54 int main()
55 {
56     //freopen("in.txt","r",stdin);
57     init();
58     int n,m;
59     while(cin>>n>>m)
60     {
61         if(n==2&&m==2)
62         {
63             cout<<1<<endl;
64         }
65         else
66         {
67             cout<<Lucas(n+m-4,m-2,mod)<<endl;
68         }
69     }
70     return 0;
71 }
View Code

 

推荐阅读