Description

定义a^b为a的b次方,并且^是满足右结合的,即a^b^c^d=a^(b^(c^d))。例如,2^3^2=2^(3^2)=2^9=512。
现在给定n个数a1,a2,…,an 求a1^a2^…^an对p取模的值。

Solution

主要目标

解决axmodp

解决方法

我们往欧拉定理上面想,首先保证a与p互质,那么axmodp=axmodφ(p)modp,因为aφ(p)≡1(modp),所以aφ(p)∗aφ(p)∗……∗aφ(p)≡1(modp),那么x=k∗φ(p)+xmodφ(p),所以axmodp=axmodφ(p)modp。
我们要让他们互质
那么我们就要先除以他们的最小公倍数
设d=gcd(a,p),b=a/d,c=p/d,ans=axmodp
所以b与c互质
把b和c带入ans
dx∗bx≡ans(modc∗d)
同时除以d
dx−1∗bx≡ansd(modc)
现在b就与c互质了,那么我们带入上面的证明
dx−1∗bxmodφ(p)≡ansd(modc)

注意

当x=1的时候,d−1就是求d关于c的逆元
每一层的mod是不一样的,用一个递归去实现。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=105;
int i,j,k,l,t,n,m,mo1;
int a[maxn],phi[10000007],zhi[10000007];
bool bz[10000007];
ll ans;
ll qsm(ll x,ll y,ll mo){
ll z=1;
while(y!=0){
if(y&1!=0)z=(z*x)%mo;
x=x*x%mo;
y /=2;
}
return z;
}
ll gcd(ll x,ll y){return (y)?gcd(y,x%y):x;}
ll dfs(int x,int mo){
if(x==n+1)return 1;
ll b,c,d=gcd(a[x],mo),l,p;
b=a[x] / d;p=mo / d;
l=dfs(x+1,phi[p]);
if(l)c=qsm(d,l-1,mo)*qsm(b,l,mo)%mo*d%mo;
else c=qsm(d,phi[p]-1,mo)*qsm(b,l,mo)%mo*d%mo;
return c;
}
int main(){
phi[1]=1;
fo(i,2,10000000){
if(!bz[i]){
phi[i]=i-1;
zhi[++zhi[0]]=i;
}
fo(j,1,zhi[0]){
t=zhi[j]*i;
if(t>10000000)break;
bz[t]=1;
if(i%zhi[j]==0){
phi[t]=phi[i]*zhi[j];
continue;
}
phi[t]=phi[i]*(zhi[j]-1);
}
}
scanf("%d",&t);
fo(i,1,t){
scanf("%d%d",&n,&mo1);
a[0]=1;
fo(j,1,n){
scanf("%d",&a[j]);
}
ans=dfs(1,mo1);
printf("%lld\n",ans);
}
}