BZOJ2982 combination

恩恩。。。数论题目

首先答案即C(n, m) % p (其中p = 10007)

于是我们想到了Lucas定理(别问窝为什么,我是蒟蒻T T):C(n, m) % p = (C(n % p, m % p) * C(n / p, m / p)) % p

这里p很小,于是左半部分"C(n % p, m % p)"只要直接暴力求就可以了:

c(x, y) = x * (x - 1) * (x - 2) * ... * (x - y + 1) / (1 * 2 * 3 * ... * y)

被除的部分再求一下逆元就可以了,方法是费马小定理:

a ^ (p - 1) ≡ 1 (mod p) (其中p为质数) => a^-1 ≡ a ^ (p - 2) mod p

而右半部分"C(n / p, m / p)"直接递归下去就可以了。

好慢啊。。。20ms。。。别人都0ms的说。。。

 1 /**************************************************************
 2     Problem: 2982
 3     User: rausen
 4     Language: C++
 5     Result: Accepted
 6     Time:20 ms
 7     Memory:804 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <algorithm>
12  
13 using namespace std;
14 typedef long long ll;
15 const int mod = 10007;
16  
17 inline int read(){
18     int x = 0;
19     char ch = getchar();
20     while (ch < '0' || ch > '9')
21         ch = getchar();
22     while (ch >= '0' && ch <= '9'){
23         x = x * 10 + ch - '0';
24         ch = getchar();
25     }
26     return x;
27 }
28  
29 inline int pow(int a, int b){
30     int res = 1;
31     while (b){
32         if (b & 1) res *= a, res %= mod;
33         a *= a, a %= mod;
34         b >>= 1;
35     }
36     return res;
37 }
38  
39 int getc(int x, int y){
40     if (x < y) return 0;
41     y = min(y, x - y);
42     int i;
43     ll res1 = 1, res2 = 1;
44     for (i = 0; i < y; ++i){
45         res1 *= (x - i), res1 %= mod;
46         res2 *= (i + 1), res2 %= mod;
47     }
48     return res1 * pow(res2, mod - 2) % mod;
49 }
50  
51 int Lucas(int x, int y){
52     return !y ? 1 : (getc(x % mod, y % mod) * Lucas(x / mod, y / mod)) % mod;
53 }
54  
55 int main(){
56     int T = read();
57     int x, y;
58     while (T--){
59         x = read(), y = read();
60         printf("%d
", Lucas(x, y));
61     }
62     return 0;
63 }
View Code
By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
原文地址:https://www.cnblogs.com/rausen/p/4083668.html