模板BSGS(SDOI2011计算器) 模板EXBSGS

BSGS和EXBSGS是OI中用于解决A^xΞB(mod C)的常用算法。

1.BSGS

BSGS用于A,C互质的情况。

令m=sqrt(C),此时x可表示为i*m+j。

式中i和j都<=sqrt(C)

原式Ax≡B(mode C) -->Ai*m * Aj≡B(mode C)

枚举Ai*m,此时Ai*m相当于系数。//O(sqrt(C))

现在我们可用exgcd/费马小定理求逆元算出Aj%C的值

通过预处理将A1~m存入map/哈希表。//O(1)//用map会多一个log

解决了。

时间复杂度O(sqrt(C)),思想类似meet_in_the_middle。

代码:

#include<map>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
ll fastpow(ll x,int y,int mod)
{
    ll ret = 1ll;
    while(y)
    {
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ret;
}
void ORZ(){printf("Orz, I cannot find x!\n");}
ll F2(ll y,int z,int p)
{
    ll tmp = fastpow(y,p-2,p);
    tmp = tmp*z%p;
    return tmp;
}
int hed[60050],cnt=0;
struct EG
{
    int to,w,nxt;
}e[70050];
void ae(int f,int t,int w)
{
    e[++cnt].to = t;
    e[cnt].w=w;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
int find(int x)
{
    int now = x%60000;
    for(int j=hed[now];j;j=e[j].nxt)
        if(e[j].to==x)
            return e[j].w;
    return -1;
}
void BSGS(ll y,int z,int p)
{
    if(!y&&z){ORZ();return ;}
    cnt=0;
    memset(hed,0,sizeof(hed));cnt=0;
    ae(1,1,0);
    int m = (int)sqrt(p);
    ll now = 1;
    for(int i=1;i<=m;i++)
    {
        now = now*y%p;
        if(find(now)==-1)
        {
            ae(now%60000,now,i);
        }
    }
    ll u = 1;
    for(int i=0;i<=m+2;i++)
    {
        ll tmp = F2(u,z,p);
        ll ans = find(tmp);
        if(~ans)
        {
            printf("%lld\n",(ans+i*m)%p);
            return ;
        }
        u=u*now%p;
    }
    ORZ();
}
int T,K,y,z,p;
int main()
{
    scanf("%d%d",&T,&K);
    while(T--)
    {
        scanf("%d%d%d",&y,&z,&p);
        y%=p;
        if(K==1)printf("%lld\n",fastpow(y,z,p));
        else if(K==2)
        {
            z%=p;
            if(!y&&z){ORZ();continue;}
            printf("%lld\n",F2(y,z,p));
        }else
        {
            z%=p;
            BSGS(y,z,p);
        }
    }
    return 0;
}

2.EXBSGS

EXBSGS用于解决C不一定是质数的问题。

对于方程Ax≡B(mode C)(gcd(A,C)!=1):

设d=gcd(A,C)。

如果B%d!=0的话,要么B==0,要么无解。

这时我们可以将三者同时/d,得到:

(A/d)*Ax-1≡ B/d (mode C/d)

此时A和C/d依然可能不互质(比如A=5,C=25)。

循环这个过程就可以啦。

我们最后得到的方程形式为:

(Ai/∏d)*Ax-i ≡ B/∏d(mode C/∏d)

其实就是D*Ax-i≡ B’(mode C’),然后套BSGS就好了。

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
void ORZ()
{
    printf("No Solution\n");
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1,y=0;
        return ;
    }
    exgcd(b,a%b,y,x);
    y-=a/b*x;
}
ll inv(ll a,ll b)
{
    ll x,y;
    exgcd(a,b,x,y);
    return (x%b+b)%b;
}
ll gcd(ll x,ll y)
{
    return y?gcd(y,x%y):x;
}
ll F2(ll y,ll z,ll p)
{
    y%=p,z%=p;
    ll ret = inv(y,p);
    return ret*z%p;
}
int hed[40050],cnt;
struct EG
{
    ll to,nxt,w;
}e[100050];
void ae(ll f,ll t,ll w)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    e[cnt].w = w;
    hed[f] = cnt;
}
ll find(ll x)
{
    for(int j=hed[x%40000];j;j=e[j].nxt)
        if(e[j].to==x)
            return e[j].w;
    return -1;
}
ll BSGS(ll y,ll z,ll p)
{
    memset(hed,0,sizeof(hed));cnt=0;
    ae(1,1,0);
    y%=p,z%=p;
    if(!y&&z)
    {
        ORZ();
        return -1;
    }
    ll now = 1ll,m = (ll)sqrt(p);
    for(int i=1;i<=m;i++)
    {
        now=now*y%p;
        if(find(now)==-1)
            ae(now%40000,now,i);
    }
    ll u = 1ll;
    for(int i=0;i<=m+2;i++)
    {
        ll tmp = F2(u,z,p);
        ll ans = find(tmp);
        if(~ans)
            return ans+i*m;
        u=u*now%p;
    }
    ORZ();
    return -1;
}
void EXBSGS(ll y,ll z,ll p)
{
    if(!y&&z){ORZ();return ;}
    if(z==1){printf("0\n");return ;}
    ll d = gcd(y,p),cnt=0,D=1ll;
    while(d!=1)
    {
        if(z%d){ORZ();return ;}
        cnt++;
        z/=d,p/=d;
        D=D*(y/d)%p;
        d=gcd(y,p);
        if(D==z){printf("%lld\n",cnt);return ;}
    }
    ll ans = BSGS(y,z*inv(D,p)%p,p);
    if(ans!=-1)printf("%lld\n",(ans+cnt)%p);
}
ll y,z,p;
int main()
{
    while(scanf("%lld%lld%lld",&y,&p,&z))
    {
        if(!y&&!z&&!p)break;
        EXBSGS(y,z,p);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/LiGuanlin1124/p/10046045.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值