HDU5407.CRB and Candies(数论)
官方题解:
The problem is just to calculate g(N) = LCM(C(N,0),C(N,1),...,C(N,N))
Introducing function f(n) = LCM(1,2,...,n), the fact g(n) = f(n+1)/(n+1) holds.
We calculate f(n) in the following way.
f(1)=1
If n =p^k,then f(n) = f(n−1)× p, else f(n) = f(n−1).
Time complexity:O(N⋅logN)
这题用学的知识:
1。乘法逆元
求(a/b)%c时 化成 (a%c)/(b%c)是错误的,所以需要用到乘法逆元。(a%c)*(b^-1%c)。
b^-1的求法:
费马小定理(Fermat Theory): 假如p是质数,且Gcd(a,p)=1,那么 a^(p-1)(mod p)≡1。
由此可得a*a^(p-2)=1 (mod p) 即a^(p-2)就是a的乘法逆元。通过快速幂可求。
2。LCM(C(N,0),C(N,1),...,C(N,N))=LCM(1,2,...,n)/(n+1)
知乎上看到有人证明,并没有看懂。http://www.zhihu.com/question/34859879
3。求LCM(1,2,...,n)的简便算法
If n =p^k,then f(n) = f(n−1)× p, else f(n) = f(n−1).
代码:
#include <iostream> #include <cstdio> #include <cstring> typedef long long ll; const int N = 1000002; const ll MOD = 1000000007; int v[N + 5]; ll f[N + 5]; int is_p[N + 5]; int p[N + 5]; int cnt_p; int n; void get_p() { for (int i = 0; i <= N; ++i) is_p[i] = 1; cnt_p = 0; is_p[0] = is_p[1] = 0; for (int i = 2; i <= N; ++i) { if (is_p[i]) { p[cnt_p++] = i; for (int j = i * 2; j <= N; j += i) is_p[j] = 0; } } } ll pow(ll a, ll b) { ll res = 1; while (b > 0) { if (b & 1) res = res * a % MOD; a = a * a % MOD; b >>= 1; } return res; } ll MIM(ll a) { return pow(a, MOD-2); } void get_f() { for (int i = 0; i < cnt_p; ++i) { ll j = 1; while (j < N) { v[j] = p[i]; j *= p[i]; } } f[1] = 1; for (int i = 2; i <= N; ++i) { if (v[i]) f[i] = f[i - 1] * v[i] % MOD; else f[i] = f[i - 1]; } } int main() { get_p(); get_f(); int t; scanf("%d", &t); while (t--) { scanf("%d", &n); printf("%lld\n", f[n + 1] * MIM(n + 1) % MOD); } return 0; }