AT_tenka1_2017_f
一个很妙的数论题,feecle6418 过来讲课的时候讲的,思路还是很有参考价值的,写篇题解记录一下。
主要是另外两篇题解都有点让人迷糊,有幂塔的那篇感觉不咋清楚,yangchenxiao 的那篇感觉少一点推理过程,我就想写一篇清楚一点的,把这个题思考的过程给写清楚,也算是对 yangchenxiao 题解的补充,毕竟这个题代码很简单主要就是怎么想出来的比较难。
以下推导过程中
思路
首先看到
这样子珂以自然得出两个式子
我们珂以假使这个
虽然
这个时候我们发现这个
这也就是那篇题解中的
还有就是一个有趣的地方
还有注意运算会非常大,你要么用龟速乘要么开 ___int128,要不然只有 long long 会爆。
代码实现珂以看看,思路更重要,其实感觉用扩欧解同余方程似乎直观一点。
code
#include<bits/stdc++.h>
using namespace std;
#define ll __int128
const ll N=2*114514,M=1919810;
inline ll read(){
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
inline void write(ll x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
return;
}
ll T,ans,a,p,pm;
ll qpow(ll a,ll b,ll mod){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
ll calc_phi(ll n){
if(n==1) return 1;
ll phi=n;
for(int i=2;i<=sqrtl(n);++i){
if(n%i==0) phi=phi/i*(i-1);
while(n%i==0) n/=i;
}
if(n>1) phi=phi/n*(n-1);
return phi;
}
ll solve(ll a,ll p){
if(p==1) return 1; //面白い
ll pm=calc_phi(p),gcd=__gcd(p,pm);
ll lcm=p*pm/gcd,u=solve(a,pm),ans;
ans=qpow(a,u,lcm);
if(ans<1) ans+=lcm;//不是0就行了
return ans;
}
int main(){
T=read();
while(T--){
ans=0;
a=read(),p=read();
if(a==0){ //这两个特判很简单
write(p),putchar('\n');
continue;
}
if(a==1){
printf("1\n");
continue;
}
write(solve(a,p)),putchar('\n');
}
return 0;
}
其实这个题我还是有个地方不懂,就是 feecle6418 来讲课的时候他是推出了