B Semi-Puzzle: Brain Storm

题目大意

给定a和p,求满足au=u (p)a^u=u \ (p)的u

解题思路

注:以下的等号皆为同余号,不是真正的等号!\\ 考虑欧拉定理,因为au=au%φ(p))a^u=a^{u \% \varphi(p))},所以假设存在一个u满足题意,则有au=au%φ(p))=aj=j+kφ(p)a^u=a^{u \% \varphi(p))}=a^j=j+k*\varphi(p),其中j=u%φ(p),k>=0j=u \% \varphi(p),k>=0,所以如果我们考虑枚举jj00φ(p)1\varphi(p)-1,那么对于每一个j,只需要判断是否存在一个大于等于0的k满足aj=j+kφ(p)a^j=j+k*\varphi(p),把ajja^j-j看做c,φ(p)\varphi(p)看作a,所以就变成了判断是否存在一个k满足ak=c  (φ(p))ak=c\ \ (\varphi(p)),这显然是一个线性同余方程,而方程有解的情况就是gcd(φ(p),p)(ajj)gcd(\varphi(p),p)|(a^j-j),而题目保证有解,所以我们只需要考虑什么j可以满足aj=j  (gcd(φ(p),p))a^j=j\ \ (gcd(\varphi(p),p)),显然就变成了原问题的一个子问题,所以我们递归解决,当模数为1时返回0即可。现在我们已经求出了j,而我们要的应该是满足题意的u,即u=j+kφ(p)u=j+k*\varphi(p),所以将递归得到的j套入同余方程中得到k,最后算出u即可。

细节问题

注意a和p和互质问题,当a和p不互质时欧拉定理要加上φ(p)\varphi(p),求解关于k的同余方程时因为aja^j很大,不能直接算出来,所以在快速幂算的时候注意a%(bc)b=ab %c\frac{a\%(b*c)}{b}=\frac{a}{b} \ \%c这个式子就行

参考代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 1e8;
int phi(int x){
    int res=x;
    for(int i=2;i<=x/i;i++){
        if(x%i==0)res=res/i*(i-1);
        while(x%i==0)x/=i;
    }
    if(x!=1)res=res/x*(x-1);
    return res;
}
int exgcd(int a, int b, int& x, int& y)
{
    if (!b)
    {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int qmi(int a,int b,int p){
    int res=1;
    a%=p;
    while(b){
        if(b&1)res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}
int huang(int a,int p){
    if(p==1)return 0;
    int m=phi(p);
    int j=huang(a%__gcd(m,p),__gcd(m,p));
    j+=m;
    int x,y;
    int d=exgcd(m,p,x,y);
    int mod=p/d;
    int ans=0;
    ans=(((x*(qmi(a,j,mod*d)-j+mod*d))%(mod*d)+(mod*d))%(mod*d)/d);
    return ans*m+j;
}
signed main(){
    int t;
    cin>>t;
    while(t--){
        int a,m;
        cin>>a>>m;
        int ans=huang(a,m);
        cout<<ans<<endl;
    }
}