题意
思考
简要题意:给定 (G, n),求:
[G^{sum_{k|n}C_n^k} (mod 999911659)
]
由于模数为质数,根据费马小定理:
[G^{sum_{k|n}C_n^k} equiv G^{sum_{k|n}C_n^k mod 999911658} (mod 999911659)
]
由于要求出模意义下的组合数,外加模数并非质数,我们可以考虑用扩展 (Lucas) 定理:
(999911658 = 2 * 3 * 4679 * 35617)
用中国剩余定理合并一下这四个同余方程组就行了:
[left{
egin{aligned}
x & equiv a_1 (mod 2)\
x & equiv a_2 (mod 3)\
x & equiv a_3 (mod 4679)\
x & equiv a_4 (mod 35617)\
end{aligned}
ight.]
[a_i=sum_{k|n}C_n^k(mod p_i) (p_i=2/3/4679/35617)
]
注意特判一下,费马小定理成立的条件是模为质数且与底数互质,当 (G mod 999911659 = 0) 时直接输出 (0)
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 100010;
ll qpow(ll x, ll p, ll mod){
ll ans = 1, base = x;
while(p){
if(p & 1) ans = (ans * base) % mod;
base = (base * base) % mod;
p >>= 1;
}
return ans;
}
ll fact[N], A[N];
ll B[N] = {0, 2, 3, 4679, 35617};
ll init(ll mod){
fact[0] = 1;
for(ll i=1; i<=mod; i++) fact[i] = (fact[i-1] * i) % mod;
}
ll C(ll n, ll m, ll mod){
if(n < m) return 0;
return fact[n] * qpow(fact[m], mod-2, mod) % mod * qpow(fact[n-m], mod-2, mod) % mod;
}
ll lucas(ll n, ll m, ll mod){
if(n < m) return 0;
if(m == 0) return 1;
return lucas(n/mod, m/mod, mod) * C(n%mod, m%mod, mod) % mod;
}
ll x, y;
ll exgcd(ll a, ll b, ll &x, ll &y){
if(b == 0){
x = 1; y = 0; return a;
}
ll ans = exgcd(b, a%b, x, y);
ll tmp = x; x = y; y = tmp - a / b * y;
return ans;
}
ll CRT(){
ll M = 999911658, ans = 0;
for(ll i=1; i<=4; i++){
ll a = M / B[i], b = B[i];
exgcd(a, b, x, y);
x = (x + B[i]) % B[i];
ans = (ans + x * a % M * A[i] % M) % M;
}
return (ans + M) % M;
}
ll n, G, tmp;
int main(){
cin >> n >> G;
if(G % 999911659 == 0){
cout << 0;
return 0;
}
for(ll k=1; k<=4; k++){
init(B[k]);
for(ll i=1; i*i<=n; i++){
if(n % i == 0){
A[k] = (A[k] + lucas(n, i, B[k])) % B[k];
if(i * i != n){
A[k] = (A[k] + lucas(n, n / i, B[k])) % B[k];
}
}
}
}
cout << qpow(G, CRT(), 999911659);
return 0;
}
总结
总结一下这一题的思路:
- 分析题目得出式子
- 由于要求幂,指数巨大且模数为质数,想到费马小定理
- 指数为组合数,而快速求出组合数取模,用 (Lucas) 定理
- 直接 (Lucas) 搞不了,用扩展 (Lucas) ( (+CRT) )
总之如果会以上几个数论定理的话这题并不难想,主要是套了很多板子,板子要掌握好啊……