2023牛客暑期多校训练营9 B.Semi-Puzzle: Brain Storm

文章目录

题目大意

给定两个数 a , m a,m a,m ,求满足 a u ≡ u ( m o d m ) a^u \equiv u (mod\ \ m) au≡u(mod m) 的一个解。
( 1 ≤ a , m ≤ 1 0 9 , 0 ≤ u ≤ 1 0 18 ) (1\leq a,m \leq10^9 ,0\leq u\leq 10^{18}) (1≤a,m≤109,0≤u≤1018)

题解

参考了讨论区 https://blog.nowcoder.net/n/576f9463036346f0a0fb04fee50fac75 的方法

求解

考虑使用欧拉定理,考虑 b > = ϕ p b>=\phi_p b>=ϕp的情况。
a u ≡ { a u % ϕ m g c d ( a , u ) = 1 a u % ϕ i + ϕ m g c d ( a , u ) ! = 1 ( m o d m ) a^u\equiv\begin{cases}a^{u\% \phi_m }&gcd(a,u)=1\\a^{u\% \phi_i+\phi_m}& gcd(a,u)!=1\end{cases}(mod \ m) au≡{au%ϕmau%ϕi+ϕmgcd(a,u)=1gcd(a,u)!=1(mod m)

定义 d = u % ϕ m d=u\%\phi_m d=u%ϕm 或 u % ϕ m + ϕ m u\%\phi_m+\phi_m u%ϕm+ϕm 和
k ∗ ϕ p + d = u ( k > = 0 ) k*\phi_p+d=u(k>=0) k∗ϕp+d=u(k>=0)

则原式可以转化为 a d ≡ d + k ∗ ϕ m ( m o d m ) a^d \equiv d+k*\phi_m (mod\ m) ad≡d+k∗ϕm(mod m)

移项可以得到 a d − d ≡ k ∗ ϕ m ( m o d m ) a^d-d\equiv k*\phi_m(mod\ m) ad−d≡k∗ϕm(mod m)
ϕ m ∗ x 1 + m ∗ y 1 ≡ g c d ( ϕ m , m ) ( m o d m ) \phi_m*x1+m*y1\equiv gcd(\phi_m,m) (mod \ m) ϕm∗x1+m∗y1≡gcd(ϕm,m)(mod m) 是一个已知有解的同余方程

回到上一个方程想要得到解 k k k ,显然要满足 a d − d = x ∗ g c d ( m , ϕ m ) , ( x > 0 ) a^d-d=x *gcd(m,\phi_m),(x>0) ad−d=x∗gcd(m,ϕm),(x>0)

也就是 a d ≡ d ( m o d g c d ( m , ϕ m ) ) a^d \equiv d (mod \ gcd(m,\phi_m)) ad≡d(mod gcd(m,ϕm))。

重新得到了题目,但是模数缩小了,因此我们想到了递归,直到模数为 1 1 1 时直接推出答案。

回溯

假设我们已经得到了最后一组解 d = 0 d=0 d=0 ,

求解同余方程 a d − d ≡ k ∗ ϕ m ( m o d m ) a^d-d\equiv k*\phi_m(mod\ m) ad−d≡k∗ϕm(mod m),使用扩展欧几里得定理,推出 x 1 x1 x1 的值,
k = x 1 ∗ a d − d g c d ( m , ϕ m ) % m o d k=x1*\frac{a^d-d}{gcd(m,\phi_m)}\%mod k=x1∗gcd(m,ϕm)ad−d%mod

由于 a d a^d ad 超出范围,根据 a b % ( b ∗ c ) = a % ( b ∗ c ) b \frac{a}{b}\%(b*c)=\frac{a\%(b*c)}{b} ba%(b∗c)=ba%(b∗c)得出
k = x 1 ∗ ( a d − d ) % m / ϕ m k=x1*(a^d-d)\%m/\phi_m k=x1∗(ad−d)%m/ϕm 。

再利用 k ∗ ϕ p + d = u k*\phi_p+d=u k∗ϕp+d=u,得出结果即可。

参考代码

cpp 复制代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll phi(ll x)
{
    ll ans=x;
    for(int i=2;i*i<=x;i++)
    {
        if(x%i==0)
            ans=ans/i*(i-1);
        while(x%i==0)
            x/=i;
    }
    if(x!=1)
        ans=ans/x*(x-1);
    return ans;
}
ll ksm(ll a,ll b,ll p)
{
    ll res=1;
    while(b)
    {
        if(b&1)
            res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    ll k=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return k;
}
int n,T;
ll a,m;
ll work(ll a,ll p)              //递归求解
{
    if(p==1)
        return 0;
    ll m=phi(p);
    ll b=work(a,__gcd(m,p))+m;
    ll x,y;
    ll d=exgcd(m,p,x,y);
    ll k=(((x*(ksm(a,b,p)-b+p))%p+p)%p/d);   //回溯求值
    return k*m+b;
}
int main()
{
    cin>>T;
    while(T--)
    {
        scanf("%lld%lld",&a,&m);
        printf("%lld\n",work(a,m));
    }
}
相关推荐
别NULL15 分钟前
机试题——疯长的草
数据结构·c++·算法
CYBEREXP20081 小时前
MacOS M3源代码编译Qt6.8.1
c++·qt·macos
yuanbenshidiaos2 小时前
c++------------------函数
开发语言·c++
yuanbenshidiaos2 小时前
C++----------函数的调用机制
java·c++·算法
tianmu_sama2 小时前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
羚羊角uou2 小时前
【C++】优先级队列以及仿函数
开发语言·c++
姚先生972 小时前
LeetCode 54. 螺旋矩阵 (C++实现)
c++·leetcode·矩阵
FeboReigns2 小时前
C++简明教程(文章要求学过一点C语言)(1)
c语言·开发语言·c++
FeboReigns3 小时前
C++简明教程(文章要求学过一点C语言)(2)
c语言·开发语言·c++
264玫瑰资源库3 小时前
从零开始C++棋牌游戏开发之第二篇:初识 C++ 游戏开发的基本架构
开发语言·c++·架构