题目链接:点击打开链接
Everybody loves big numbers (if you do not, you might want to stop reading at this point). There are many ways of constructing really big numbers known to humankind, for instance:
- Factorials: 2016!=2016 ⋅ 2015 ⋅ ... ⋅ 2 ⋅ 1.
In this problem we look at their lesser-known love-child the exponial, which is an operation defined for all positive integers n as
exponial(n)=n(n − 1)(n − 2)⋯21
For example, exponial(1)=1 and exponial(5)=54321 ≈ 6.206 ⋅ 10183230 which is already pretty big. Note that exponentiation is right-associative: abc = a(bc).
Since the exponials are really big, they can be a bit unwieldy to work with. Therefore we would like you to write a program which computes exponial(n) mod m (the remainder of exponial(n) when dividing by m).
Input
There will be several test cases. For the each case, the input consists of two integers n (1 ≤ n ≤ 109) and m (1 ≤ m ≤ 109).
Output
Output a single integer, the value of exponial(n) mod m.
Sample Input
2 42 5 123456789 94 265
Sample Output
2 16317634 39
(二)解题思路:
- 直接快速幂的复杂度为O(CN)的,显然不行。
- 数学题目做得少,其实没有什么太多好说的,这个题就是考了一欧拉降幂公式(具体的证明过程请移步百度或Wiki^_^):
其中的ψ()为欧拉函数(不懂的话同上)。
3.我们可以发现每次我们可以将模数由C降为ψ(C),这里不加证明地给出结论,这个降地速度是log级别的,而当模数为1时,结果当然就是0,所以我们按照以上式子递归求解即可得到结果。注意一点的是上式成立的条件为A^B(A的B次方)>C(?),所以应当预处理出n<=4时的结果。
(三)具体代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#define LL long long
using namespace std;
LL know[]={1,1,2,9,262144};
LL phi(LL n){
LL res=n,m=n;
for(int i=2;i*i<=n;i++){
if(m%i==0){
res-=res/i;
while(m%i==0)m/=i;
}
}
if(m>1)res-=res/m;
return res;
}
LL ksm(LL a,LL b,LL mod){
LL res=1;
while(b){
if(b&1)res=res*a%mod;
b>>=1;a=a*a%mod;
}
return res;
}
LL solve(LL n,LL mod){
if(mod==1)return 0;
if(n<=4)return know[n]%mod;
LL PHI=phi(mod);
LL Next=solve(n-1,PHI);
return ksm(n,Next+PHI,mod);
}
int main(){
freopen("in.txt","r",stdin);
LL n,m;
while(cin>>n>>m){cout<<solve(n,m)<<endl;}
return 0;
}
表示数学是真的神奇!!!