【Tenka1 Programmer Contest 2017 F】ModularPowerEquation!!(欧拉定理)

来源:互联网 发布:淘宝外宣兼职违法吗 编辑:程序博客网 时间:2024/05/17 01:29

题目大意

输入A,M,找任意一个K ,使得AKK(mod M)

题解

欧拉定理

若n,a互质,则

aϕ(n)1(mod n)

证明:
令1~n中,与n互质的数为x1,x2,x3,...,xϕ(n)
mi=axi,

  1. 性质1:所有mi中,任意两个都不关于n同余。
    若存在 mimj(mod n)
    n|mimjn|a(xixj),∵n与a互质,xixj<nn不整除a(xixj),矛盾。
  2. 性质2:所有mi mod n与n互质。
    mi=pn+r,若r与n有公因子q,则mi也一定有因子q,min不互质
    ∵a与n互质,x_i与n互质,axi不含n的任何因子,矛盾。

由以上性质得出
m1,m2,m3,...,mϕ(n)所有数模n,得到的数一定是x1,x2,x3,...,xϕ(n)
m1m2m3...mϕ(n)x1x2x3...xϕ(n)(mod n)
(aϕ(n)1)x1x2x3..xϕ(n)0(mod n)
n|(aϕ(n)1)x1x2x3..xϕ(n)
n|aϕ(n)1
aϕ(n)1(mod n)

缩小问题规模

AKK(mod M)
Aϕ(M)...Aϕ(M)AK mod ϕ(M)K(mod M)
Aϕ(M)1(mod M)
AK mod ϕ(M)K(mod M)

找一个t,使得tK(mod ϕ(M))
AtAKK(mod M)
At mod M=t mod ϕ(M)
Att(mod gcd(M,ϕ(M)))
然后问题变为求t,M缩小。

具体实现

当M=1时,K=1。

O(M)暴力求出ϕ(M),取gcd(M,ϕ(M))递归求解,得到一个t.
根据以下条件
AtK(mod M)
At mod M=t mod ϕ(M)=K
得出
x×M+At mod M=y×ϕ(M)+t mod ϕ(M)
x×My×ϕ(M)=t mod ϕ(M)At mod M
可用扩展欧几里得解出这个不定方程的x.
为保证得到正数,适当的把t扩大,加上几个ϕ(M)使等式右边变为正数.
解出x后
K=x×M+At mod M

代码

#include<cstdio>long long modpow(long long a,long long b,long long p){    long long ret=1;    for(;b>0;b>>=1,a=(a*a)%p)        if(b&1)            ret=(ret*a)%p;    return ret;}long long phi(long long n){    long long res=n,t=n;    for(long long i=2;i*i<=t;i++)        if(t%i==0)        {            res-=res/i;            while(t%i==0)                t/=i;        }    if(t>1)        res-=res/t;    return res;}long long gcd(long long a,long long b){    if(b==0)        return a;    return gcd(b,a%b);}long long exgcd(long long a,long long b,long long &x,long long &y){    if(b==0)    {x=1;y=0;return a;}    long long g;    g=exgcd(b,a%b,y,x);    y-=a/b*x;    return g;}long long solve(long long A,long long M){    if(M==1)        return 1;    long long pM,At,d,t,x,y;    pM=phi(M);    d=gcd(M,pM);    t=solve(A,d);    At=modpow(A,t,M);    exgcd(M/d,pM/d,x,y);    x=x*(((t-At)%pM+pM)%pM)/d;    x=((x%(pM/d))+pM/d)%(pM/d)+pM/d;    return x*M+At;}int main(){    int Q;    long long A,M;    scanf("%d",&Q);    while(Q--)    {        scanf("%lld%lld",&A,&M);        printf("%lld\n",solve(A,M));    }    return 0;}
原创粉丝点击