POJ-3243-Clever Y-扩展Bsgs算法-已知a,c,p,和a^b=c(mod p),求b

POJ-3243-Clever Y-扩展Bsgs算法-已知a,c,p,和a^b=c(mod p),求b

【Description】

Little Y finds there is a very interesting formula in mathematics:

X Y m o d   Z = K X^Y mod\:Z=K XYmodZ=K

Given X, Y, Z, we all know how to figure out K fast. However, given X, Z, K, could you
figure out Y fast?

【Input】

Input data consists of no more than 20 test cases. For each test case, there would be 
only one line containing 3 integers X, Z, K (0 ≤ X, Z, K ≤ 10^9).
Input file ends with 3 zeros separated by spaces. 

【Output】

For each test case output one line. Write "No Solution" (without quotes) if you cannot
find a feasible Y (0 ≤ Y < Z). Otherwise output the minimum Y you find. 

【Examples】

Sample Input
5 58 33
2 4 3
0 0 0
Sample Output
9
No Solution

【Problem Description】

对于题目给的式子,已知X,Z,K,求Y.

【Solution】

扩展BSGS
因为X,Z不一定为互质,无法求逆元。所以不能直接用BSGS来做,需要做一些处理。

X Y = K ( m o d &MediumSpace; Z ) = X Y − 1 X d = K d ( m o d Z d ) , 其 中 d = g c d ( X , Z ) . 不 断 重 复 此 过 程 , 直 到 g c d ( X , Z ∏ i d i ) = 1 , 即 : X Y − k X k ∏ i d i = K ∏ i d i ( m o d Z ∏ i d i ) 注 意 在 此 过 程 中 , 对 于 每 个 d i , K % d i = = 0 , 若 K % d i ! = 0 , 则 无 解 最 后 去 掉 分 母 得 : X Y = K ( m o d Z ∏ i d i ) , 将 其 直 接 应 用 B S G S 即 可 。 X^Y=K(mod\:Z)= X^{Y-1}\frac{X}{d}=\frac{K}{d}(mod\frac{Z}{d}),其中d=gcd(X,Z).\\ 不断重复此过程,直到gcd(X,\frac{Z}{\prod_{i}d_i})=1,即:\\ X^{Y-k}\frac{X^k}{\prod_{i}d_i}=\frac{K}{\prod_{i}d_i}(mod \frac{Z}{\prod_{i}d_i})\\ 注意在此过程中,对于每个d_i,K\%d_i==0,若K\%d_i!=0,则无解\\ 最后去掉分母得:\\ X^Y=K(mod \frac{Z}{\prod_{i}d_i}),将其直接应用BSGS即可。 XY=K(modZ)=XY1dX=dK(moddZ),d=gcd(X,Z).gcd(X,idiZ)=1,XYkidiXk=idiK(modidiZ)di,K%di==0,K%di!=0,XY=K(modidiZ),BSGS

BSGS:

a b = c ( m o d &MediumSpace; p ) 令 m = ⌈ q ⌉ , 则 可 以 暴 力 求 出 b = [ 1 , m ) 的 时 候 的 c , 用 m a p 保 存 起 来 。 b = [ m , p ] 时 : 必 然 等 于 a i a k m = c ( m o d &MediumSpace; p ) 则 a i = c &MediumSpace; a − k m ( m o d &MediumSpace; p ) ( 其 中 i &lt; m ) 即 b = [ m , p ] 时 通 过 已 求 得 的 值 来 查 询 他 们 的 答 案 。 知 道 c a − k m 的 值 即 可 知 道 i 的 值 。 则 答 案 就 为 i + k m , c ⋅ a − k m 的 值 可 以 通 过 求 a m 的 逆 元 乘 以 c , 然 后 枚 举 次 数 k 即 可 。 a^b=c(mod\:p)\\ 令m=\lceil\sqrt{q}\rceil,则可以暴力求出b=[1,m)的时候的c,用map保存起来。\\ b=[m,p]时:\\ 必然等于a^ia^{km}=c(mod\:p)\\ 则a^i=c\:a^{-km}(mod\: p)(其中i&lt;m)\\ 即b=[m,p]时通过已求得的值来查询他们的答案。知道ca^{-km}的值即可知道i的值。\\ 则答案就为i+km,c\cdot a^{-km}的值可以通过求a^m的逆元乘以c,然后枚举次数k即可。 ab=c(modp)m=q ,b=[1,m)cmapb=[m,p]aiakm=c(modp)ai=cakm(modp)(i<m)b=[m,p]cakmii+kmcakmamck

用STL的map会超时,所以得手写HashMap.

【Code】

/*
 * @Author: Simon 
 * @Date: 2018-09-27 20:45:58 
 * @Last Modified by: Simon
 * @Last Modified time: 2018-09-27 21:46:57
 */
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<cstdio>
#include<cmath>
using namespace std;
typedef int Int;
#define int long long
#define INF 0x3f3f3f3f
#define maxn 1000005
const int mod = 611977;
struct HashMap //手写HashMap
{
    int head[mod+5],key[maxn],value[maxn],nxt[maxn],tol;
    inline void clear()
    {
        tol=0;memset(head,-1,sizeof(head));
    }
    HashMap()
    {
        clear();
    }
    inline void insert(int k,int v)
    {
        int idx=k%mod;
        for(int i=head[idx];~i;i=nxt[i])
        {
            if(key[i]==k) 
            {
                value[i]=min(value[i],v);
                return ;
            }
        }
        key[tol]=k;value[tol]=v;nxt[tol]=head[idx];head[idx]=tol++;
    }
    inline int operator [](const int &k) const
    {
        int idx=k%mod;
        for(int i=head[idx];~i;i=nxt[i])
        {
            if(key[i]==k) return value[i];
        }
        return -1;
    }
}mp;
inline int fpow(int a,int b,int mod) //快速幂
{
    a%=mod;int ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
inline int exgcd(int a,int b,int &x,int &y) //扩展欧几里得
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    int ans=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return ans;
}
inline int Bsgs(int a,int b,int mod)
{
    a%=mod,b%=mod;
    if(b==1) return 0; 
    int m=ceil(sqrt(mod)),inv,y;exgcd(fpow(a,m,mod),mod,inv,y);//扩展欧几里得求a^m的逆元
    inv=(inv%mod+mod)%mod;
    mp.insert(1,0); //b==1时,答案为0
    for(int i=1,e=1;i<m;i++) //暴力求[1,m)的答案
    {
        e=e*a%mod;
        if(mp[e]==-1) mp.insert(e,i);
    }
    for(int k=0;k<=m;k++) //查询答案
    {
        if(mp[b]!=-1) //如果存在
        {
            int ans=mp[b]; 
            return ans+k*m; //返回答案
        }
        b=b*inv%mod; //不断叠加次数
    }
    return -1;
}
inline int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
inline int exBsgs(int a, int b, int p) {//扩展BSGS, 处理a,mod不互质的情况
    if(b == 1) return 0;
    int tb = b, tmp = 1;
    for(int g = gcd(a, p),k=1; g != 1; g = gcd(a, p),k++) {
        if(tb % g) return -1; //保证g为a,b,p的最大公约数
        tb /= g; p /= g; tmp = tmp * a / g % p;
        if(tmp == tb) return k;
    }
    return Bsgs(a, b, p);
}
Int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int x,z,k;
    while(scanf("%lld%lld%lld",&x,&z,&k)!=EOF&&(x+z+k))
    {
        mp.clear();
        int ans=exBsgs(x,k,z); 
        if(ans!=-1) printf("%lld\n",ans);
        else puts("No Solution");
    }
    cin.get(),cin.get();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值