[SDOI2011]计算器(exgcd&BSGS)

k=1:裸的快速幂
k=2:xy=z+kp,直接exgcd,这个可以不用解释了,不懂的同学可以看代码
k=3:裸的BSGS
重点是k=3(BSGS学习)
a x=b(mod p)求解这个同余方程
只能求gcd(a,p)=1的情况。
如何求解?很容易发现解一定位于{0,p-1}之间,设q=ceil(√p),然后x可以表示成cq-d
因为a x=b(mod p),所以a cq=b*a d(mod p)
于是可以这样考虑:枚举d∈[1,q],将值插入哈希表,如有重复的则只记录最大的d,因为本题是求最小解,再枚举c=1...q,查询a cq是否在哈希表内,如果在就可以直接跳出来。
注意要特判a或b等于0的情况就可以了。
不说太多了,直接上模板:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
map<int,int>hsh;
ll y,z,p;
ll qpow(ll a,ll b)
{
    a%=p;
    ll ret=1;
    while(b)
    {
        if(b&1)ret=ret*a%p;
        a=a*a%p,b>>=1;
    }
    return ret;
}
ll exgcd(ll a,ll b,ll&x,ll&y)
{
    if(b==0){x=1,y=0;return a;}
    ll ret=exgcd(b,a%b,y,x);y-=a/b*x;
    return ret;
}
void solve2(ll a,ll b)
{
    ll x,y,ans,d,s;
    d=exgcd(a,p,x,y);
    if(b%d){puts("Orz, I cannot find x!");return;}
    ans=b/d*x;
    s=p/d;
    ans=(ans%s+s)%s;
    printf("%lld\n",ans);
}
void solve3()
{
    y%=p,z%=p;
    if(!y)
    {
        if(!z)puts("1");else puts("Orz, I cannot find x!");
        return;
    }
    ll m=ceil(sqrt(p)),v=qpow(y,p-m-1),e=1,ret;
    hsh.clear();
    hsh[1]=m+1;
    for(ll i=1;i<=m;i++)
    {
        e=e*y%p;
        if(!hsh[e])hsh[e]=i;
    }
    ret=-1;
    for(ll i=0;i<m;i++)
    {
        if(hsh[z]){ret=i*m+(hsh[z]==m+1?0:hsh[z]);break;}
        z=z*v%p;
    }
    if(ret==-1)puts("Orz, I cannot find x!");
    else printf("%d\n",ret);
}
int main()
{
    int T,k;
    scanf("%d%d",&T,&k);
    while(T--)
    {
        scanf("%lld%lld%lld",&y,&z,&p);
        if(k==1)printf("%lld\n",qpow(y,z));
        else if(k==2)solve2(y,z);
        else solve3();
    }
}
View Code

 

转载于:https://www.cnblogs.com/hfctf0210/p/10148236.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值