您的位置:首页 > 其它

bzoj 3122 : [Sdoi2013]随机数生成器 BSGS

2017-03-22 16:13 369 查看
BSGS算法

转自:http://blog.csdn.net/clove_unique

问题

给定a,b,p,求最小的非负整数x,满足$a^x≡b(mod \ p)$

题解

这就是经典的BSGS算法,方法如下:
令$x=im−j$,$m=⌈\sqrt{p}⌉$,则$a^{im−j}≡b(mod \ p)$
移项,得$(a^m)^i≡ba^j(mod \ p) $
首先,从$0−m$枚举$j$,将得到的$ba^j$的值存入hash表;
然后,从$1−m$枚举$i$,计算$(a^m)^i$,查表,如果有值与之相等,则当时得到的$im−j$是最小值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#define int long long
using namespace std;
int p;
int pw(int x,int y)
{
int lst=1;
while(y)
{
if(y&1)lst=lst*x%p;
y>>=1;
x=x*x%p;
}
return lst;
}
int xx,yy;
void exgcd(int a,int b)
{
if(b==0)
{
xx=1;yy=0;
return ;
}
exgcd(b,a%b);
int tmp=xx;
xx=yy;
yy=tmp-(a/b)*yy;
return ;
}

map<int,int>mp;
int work(int a,int b)
{
int m=ceil(sqrt(p));
mp.clear();
int now=1;
mp[now*b%p]=0;
for(int i=1;i<=m;i++)
{
now=now*a%p;
mp[now*b%p]=i;
}
int tmp=1;
for(int i=1;i<=m;i++)
{
tmp=tmp*now%p;
if(mp[tmp])
{
return  i*m-mp[tmp];
}
}
return -1;
}
int a,b,x1,t;
signed main()
{
int cas;
scanf("%lld",&cas);
while(cas--)
{
scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
if(x1==t)
{
puts("1");
continue;
}
if(a==0)
{
if(x1==t)puts("1");
else if(b==t)puts("2");
else puts("-1");
continue;
}
if(a==1)
{
if(!b)
{
if(x1==t)puts("1");
else puts("-1");
continue;
}
exgcd(b,p);
int tmp=(t-x1+p)%p;
xx=((xx*tmp%p)+p)%p;
xx++;
printf("%lld\n",xx);
}
else
{
int c=pw(a-1,p-2);
int t1=(x1+b*c)%p,t2=p,t3=(b*c+t)%p;
exgcd(t1,t2);
xx=(xx%p+p)%p;
xx=(xx*t3)%p;
int ans=work(a,xx);
if(ans!=-1)printf("%lld\n",ans+1);
else printf("%lld\n",ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: