题意:给出一个n(1~1e9),m(1~1e9),求exponial(n)%m的值
解法:有这样一个欧拉降幂的公式
(phi(x)表示x的欧拉值)
从n向1来DFS,在中间求幂时使用快速幂取膜然后就可以算出答案了~
欧拉函数:
对一个正整数N,欧拉函数是小于N且与N互质的数的个数.。
例如φ(24)=8,因为1, 5, 7, 11, 13, 17, 19, 23均和 24 互质。
φ(n) = 其中(p1.....pn)为N的素因子.
φ(24)==8.
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 500;
#define inf 0x3f3f3f3f
#define ll long long
ll biao[] = { 0,1,2,9,(1 << 18) };//题目给出的式子的n<=4的结果值
ll mod_pow(ll a, ll n, ll mod) {//快速幂
a %= mod;
ll ret = 1;
while (n) {
if (n & 1) ret = (ret*a) % mod;
a = a*a%mod;
n >>= 1;
}
return ret;
}
ll euler(ll n) { //log(n)时间内求一个数的欧拉值
ll ans = n;
for (ll i = 2; i*i <= n; i++) {
if (n%i == 0)
{
ans -= ans / i;
while (n%i == 0) n /= i;
}
}
if (n>1) ans -= ans / n;
return ans;
}
ll dfs(ll n, ll m) {
if (m == 1) return 1;
if (n <= 4) //因为当n<=4时才有可能出现幂小于等于模数的情况,其余时候都是幂大于模数
{ //所以预处理出n的最小4项结果,第5项已经远大于模数的最大值1e9了
if (biao[n] >= m) return biao[n] % m + m;
return biao[n];
}
ll exp = dfs(n - 1, euler(m));
return mod_pow(n, exp, m) + m;
}
int main() {
ll n, mod;
while (~scanf("%lld%lld", &n, &mod)) {
ll exp = dfs(n - 1, euler(mod));
ll ans = mod_pow(n, exp, mod);
printf("%lld\n", ans);
}
}