bzoj 1467: Pku3243 clever Y (扩展BSGS)

7 篇文章 0 订阅

1467: Pku3243 clever Y

Time Limit: 4 Sec   Memory Limit: 64 MB
Submit: 211   Solved: 113
[ Submit][ Status][ Discuss]

Description

小Y发现,数学中有一个很有趣的式子: X^Y mod Z = K 给出X、Y、Z,我们都知道如何很快的计算K。但是如果给出X、Z、K,你是否知道如何快速的计算Y呢?

Input

本题由多组数据(不超过20组),每组测试数据包含一行三个整数X、Z、K(0 <= X, Z, K <= 109)。 输入文件一行由三个空格隔开的0结尾。

Output

对于每组数据:如果无解则输出一行No Solution,否则输出一行一个整数Y(0 <= Y < Z),使得其满足XY mod Z = K,如果有多个解输出最小的一个Y。

Sample Input

5 58 33
2 4 3
0 0 0

Sample Output

9
No Solution

HINT

Source

ghy



题解:



注:BSGS和扩展欧几里德的应用条件都是是A,P互质,那么这道题出来下面写出的麻烦的方法,还可以直接求

A^x-k=B*inv(A^k)  (mod p')  ,inv(A^k) 用扩展欧几里德来求。

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<algorithm>  
#define ll long long  
#define q 100003  
using namespace std;  
ll a,b,p,cnt,tot;  
ll point[q<<1],v[q<<1],u[q<<1],next[q<<1];  
void add(ll x,ll y)  
{  
    ll k=x%q; tot++;  
    next[tot]=point[k];  
    u[tot]=x;  
    v[tot]=y;  
    point[k]=tot;  
}  
ll find(int x)//hash  
{  
    ll k=x%q;  
    for (ll i=point[k];i;i=next[i])  
     if (u[i]==x)  
      return v[i];  
    return -1;  
}  
ll quickpow(ll num,ll x,ll m)//快速幂  
{  
    ll ans=1; ll base=num%m;  
    while (x)  
    {  
        if (x&1)   
         ans=ans*base%m;  
        x>>=1;  
        base=base*base%m;  
    }  
    return ans%m;  
}  
ll gcd(ll x,ll y)//最大公约数  
{  
    ll r;  
    while (y)  
     {  
        r=x%y;   
        x=y;   
        y=r;  
     }  
    return x;  
}  
ll exbsgs(ll a,ll b,ll p)  
{  
    a%=p; b%=p;  
    if (b==1) return 0;  
    ll cnt=0,d=1,tmp=1;  
    while((tmp=gcd(a,p))!=1)//不断除以a,p的最大公约数,直到a,p互质  
    {  
        if (b%tmp)  return -1;  
        b/=tmp; p/=tmp; cnt++;  
        d=d*(a/tmp)%p;//记录的是A^x-cnt的系数  
        if (b==d) return cnt;  
    }  
    ll m=ceil(sqrt(p)); ll ans=b;  ll sum=1;  
    tot=0;  
    memset(point,0,sizeof(point));  
    memset(next,0,sizeof(next));  
    tmp=quickpow(a,m,p);  
    add(ans,0);  
    for (ll i=1;i<=m;i++)  
     ans=ans*a%p,add(ans,i);  
    for (ll i=1;i<=m+1;i++)  
     {  
        d=d*tmp%p;   
        ll t=find(d);   
        if (t!=-1)  
         return i*m-t+cnt;  
     }  
    return -1;  
}  
int main()  
{  
    while (scanf("%I64d%I64d%I64d",&a,&p,&b))  
     {  
        if (a==0&&b==0&&p==0) break;  
        ll t=exbsgs(a,b,p);  
        if (t!=-1)  
         printf("%I64d\n",t);  
        else 
         printf("No Solution\n");  
     }  
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值