您的位置:首页 > 其它

【poj3243-Clever Y】高次同余方程-拓展BabyStepGiantStep

2016-02-04 08:30 288 查看
http://poj.org/problem?id=3243

题意:给定X,Z,K,求一个最小的Y满足XY mod Z = K。

关于拓展BSGS的详细解释我写了一篇博文:http://www.cnblogs.com/KonjakJuruo/p/5178600.html

题解:BSGS的拓展版本(因为X和Z不一定互质)。这道题挺坑的,如果K>=Z不是输出无解而是让K%=Z。

算是BSGS的模板题,我打了两种版本,就是二分查找和hash。对比两次提交来看,二分省空间,耗时间;Hash省时间,耗空间。


  另外,find部分可以不用二分,而用hash解决。感觉大部分情况下还是hash比较快,但是比较耗空间。

  把你需要存的数,即x的0~m次方算出来,假设是t,我们设m=1<<16-1,然后用t异或^m得nt(就是取t二进制后的15位进行hash),然后存到hash表里面去。如果t的位置目前没有存数,那么我们就直接存到hash[t]上去,如果t位置已经存了数(因为后15位为t的可能有多种情况),我们就在len除增加一个位置,把nt存到那里面去,然后hash[t].next=len,把位置记录下来,这应该就相当于一条链了。查找的时候循着这条链找下去即可,链的尽头的next用-1标记。

——引用自http://www.cnblogs.com/Konjakmoyu/p/5180458.html



#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

typedef long long LL;
const LL N=40000,Max=(1<<16)-1;
bool bk;
LL X,Z,K,len;
bool vis[70000];
struct node{
LL d,id,next;
}hash[2*Max];

int exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0) {x=1,y=0;return a;}
LL tx,ty;
LL d=exgcd(b,a%b,tx,ty);
x=ty;y=tx-(a/b)*ty;
return d;
}

void ins(LL d,LL id)
{
LL t=d&Max;
if(!vis[t]) {
vis[t]=1;
hash[t].d=d,hash[t].id=id,hash[t].next=-1;
return ;
}
for(;hash[t].next!=-1;t=hash[t].next))//注意是hash[t].next!=-1
{
if(hash[t].d==d) return;
}
hash[t].next=++len;
hash[len].d=d;hash[len].id=id;hash[len].next=-1;
}

LL find(LL d)
{
LL t=d&Max;
if(!vis[t]) return -1;
for(;t!=-1;t=hash[t].next)
{
if(hash[t].d==d) return hash[t].id;
}
return -1;
}

LL BSGS()
{
LL t,g,x,y,pm,a,b,c,m,k,sum,am;
a=X;b=K;c=Z;k=1;sum=0;t=1%c;
for(int i=0;i<=100;i++){
if(t==b) return i;
t=t*a%c;
}
while((g=exgcd(X,c,x,y))!=1)
{
k=(k*X/g)%c;
c/=g;
if(b%g) return -1;
b/=g;
sum++;
}
m=(LL)(ceil((double)sqrt((double)c)));
ins(k,0);
t=k;pm=1;
for(int i=1;i<=m;i++)
{
t=t*a%c,pm=pm*a%c;
ins(t,i);
}
exgcd(pm,c,x,y);
am=x%c+c;
t=b;
for(int i=0;i<=m;i++)
{
x=find(t);
if(x!=-1) return i*m+x+sum;
t=t*am%c;
}
return -1;
}

int main()
{
// freopen("a.in","r",stdin);
// freopen("b.out","w",stdout);
while(1)
{
scanf("%I64d%I64d%I64d",&X,&Z,&K);
if(!X && !Z && !K) return 0;
K%=Z;len=Max;
memset(vis,0,sizeof(vis));
LL ans=BSGS();
if(ans!=-1) printf("%I64d\n",ans);
else printf("No Solution\n");
}
return 0;
}


BSGS-Hash
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: