题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2021
题目大意:给出n和m,定义一个函数exponial(n)=n(n − 1)(n − 2)⋯21,要你求出这个函数膜m的结果;
题目思路:由于这个幂次实在太大了,所以得采用欧拉降幂公式来处理
欧拉降幂公式:
其中代表C的欧拉函数;(C的欧拉函数等于不超过C且和C互素的整数个数)。
有了这个公式我们就可以通过递归来处理上面的幂次,将整体的大小下降好几个档次了,具体实现看代码。
AC代码如下:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define fuck(x) cout<<'['<<x<<']'<<endl
using namespace std;
typedef long long LL;
typedef pair<int,int>pii;
const int MX = 23333;
LL n,m;
LL euler(LL n){
LL m = (LL)sqrt(n+0.5);
LL ans = n;
for(int i = 2;i <= m;i++){
if(n%i == 0){
ans = ans/i*(i-1);
while(n%i == 0) n /= i;
}
}
if(n > 1) ans = ans/n*(n - 1);
return ans;
}
LL quick_pow(LL a,LL b,LL mod){
LL res = 1;
while(b){
if(b&1) res = (res*a)%mod;
a = (a * a) % mod;
b >>= 1;
}
return res;
}
LL solve(LL n,LL m){
if(m == 1) return 0;
if(n == 1) return 1;
else if(n == 2) return 2%m;
else if(n == 3) return 9%m;
else if(n == 4) return quick_pow(4,9,m);
else{
LL phi = euler(m);
LL k = solve(n-1,phi);
LL ans = quick_pow(n,phi+k,m);
return ans;
}
}
int main(){
while(~scanf("%lld%lld",&n,&m)){
printf("%lld\n",solve(n,m));
}
return 0;
}