GYM 101550 E.Exponial(指数循环定理)

Description

定义 exponial(n)=n(n1)(n2)...21 e x p o n i a l ( n ) = n ( n − 1 ) ( n − 2 ) . . . 2 1 ,求 exponial(n)%m e x p o n i a l ( n ) % m

Input

给出两个整数 n,m(1n,m109) n , m ( 1 ≤ n , m ≤ 10 9 )

Output

输出 exponial(n)%m e x p o n i a l ( n ) % m

Sample Input

2 42

Sample Output

2

Solution

简记 e(n)=exponial(n) e ( n ) = e x p o n i a l ( n ) ,由指数循环定理 AB mod C=AB mod φ(C)+φ(C) mod C(B>φ(C)) A B   m o d   C = A B   m o d   φ ( C ) + φ ( C )   m o d   C ( B > φ ( C ) ) ,由于 e(5)=5218>109 e ( 5 ) = 5 2 18 > 10 9 ,故只要 n>4 n > 4 就满足指数循环定理的条件,进而有 e(n)%m=nφ(m)ne(n1)%φ(m)%m e ( n ) % m = n φ ( m ) ⋅ n e ( n − 1 ) % φ ( m ) % m ,以此递推即可,由于欧拉函数以 2 2 的对数级别收敛到 0 0 ,故最多递归 log2m l o g 2 m 层模数就会变成 1 1 ,时间复杂度 O(log2nlog2m) O ( l o g 2 n l o g 2 m ) n4 n ≤ 4 时暴力算即可

Code

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100001;
int mod_pow(int a,int b,int c)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=(ll)ans*a%c;
        a=(ll)a*a%c;
        b>>=1;
    }
    return ans;
}
int phi(int n)
{
    int ans=n;
    for(int i=2;i*i<=n;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;
}
int Solve(int n,int m)
{
    if(m==1)return 0;
    if(n==1)return 1%m;
    if(n==2)return 2%m;
    if(n==3)return 9%m;
    if(n==4)return (1<<18)%m;
    int t=phi(m);
    int ans=(ll)mod_pow(n,phi(m),m)*mod_pow(n,Solve(n-1,phi(m)),m)%m;
    return ans;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))printf("%d\n",Solve(n,m));
    return 0;
}

你可能感兴趣的:(数论,GYM)