BZOJ_P1467/POJ_P3243 Clever Y(扩展BSGS+哈希)

来源:互联网 发布:数据库基础pdf 编辑:程序博客网 时间:2024/05/15 08:35

BZOJ-P1467
POJ-P3243

Time Limit: 4 Sec Memory Limit: 64 MB
Submit: 202 Solved: 106
[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

Sol:
扩展BSGS
这里写图片描述
两种思路
a^x=b(mod p) =>x=i*m+j
a^x=b(mod p) =>x=i*m-j
都可以做,第一种要求逆元,加小范围暴力,比较麻烦,第二种要快一些,第二种要考虑的东西比较多,还是比较好写。
ps:手打Hash大法好!

做完这题就有5倍经验了!
BZOJ-P1467
BZOJ-P3239
BZOJ-P2995
BZOJ-P2480
POJ-P3243
注意大小写和输入顺序

这是第二种做法,把x拆成i*m-j

#include<cstdio>#include<cstring>#include<cmath>#include<map>#include<algorithm>#include<iostream>using namespace std;#define Mod 99991typedef long long LL;inline LL in(LL x=0,char ch=getchar(),int v=1){    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();if(ch=='-') v=-1,ch=getchar();    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*v;}struct HashTable{LL k,v,nxt;}hash[Mod<<1];int head[Mod];int sum;void Add(LL k,LL v){    int ha=k%Mod;    hash[++sum].nxt=head[ha],hash[sum].k=k,hash[sum].v=v;head[ha]=sum;}LL find(LL k){    int ha=k%Mod;    for(int i=head[ha];~i;i=hash[i].nxt) if(hash[i].k==k) return hash[i].v;    return -1;}LL pow(LL a,LL b,LL p,LL res=1){while(b){if(b&1) res=res*a%p;a=a*a%p,b>>=1;};return res;}LL Exbsgs(LL a,LL b,LL p){    if(a%=p,b%=p,b==1) return 0;    LL tmp=1,d=1,cnt=0;    while((tmp=__gcd(a,p))!=1){        if(b%tmp) return -1;        cnt++,b/=tmp,p/=tmp,d=d*(a/tmp)%p;        if(b==d) return cnt;    }    LL m=ceil(sqrt(p)),j=b;sum=0;    memset(head,-1,sizeof(head));memset(hash,0,sizeof(hash));    for(LL i=0;i<m;i++) Add(j,i),j=j*a%p;tmp=pow(a,m,p);    for(LL i=1;i<=m+1;i++) if(d=d*tmp%p,~(j=find(d))) return i*m-j+cnt;    return -1;}int main(){    LL a,b,p,ans;    while(a=in(),p=in(),b=in(),a||b||p){        ans=Exbsgs(a,b,p);        if(~ans) printf("%lld\n",ans);else puts("No Solution");    }    return 0;}

第一种做法:
x=i*m+j

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<iostream>using namespace std;#define Mod 99991typedef long long LL;inline LL in(LL x=0,char ch=getchar(),int v=1){    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();if(ch=='-') v=-1,ch=getchar();    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*v;}struct HashTable{LL k,v,nxt;}hash[Mod<<1];int head[Mod];int sum;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;}void Add(LL k,LL v){    int ha=k%Mod;    hash[++sum].nxt=head[ha],hash[sum].k=k,hash[sum].v=v;head[ha]=sum;}LL find(LL k){    int ha=k%Mod;    for(int i=head[ha];~i;i=hash[i].nxt) if(hash[i].k==k) return hash[i].v;    return -1;}LL Exbsgs(LL a,LL b,LL p){    LL tmp=1,d=1;LL cnt=0;    for(LL i=0;i<=100;i++){          if(tmp==b) return i;        tmp=tmp*a%p;      }    while((tmp=__gcd(a,p))!=1){        if(b%tmp) return -1;        cnt++,b/=tmp,p/=tmp;        d=d*a/tmp%p;    }    LL m=ceil(sqrt(p)),j=1;sum=0;    memset(head,-1,sizeof(head));memset(hash,0,sizeof(hash));    for(LL i=0;i<m;i++) Add(j,i),j=j*a%p;    LL x,y,k;tmp=j;    for(LL i=0;i<m;i++,d=d*tmp%p){        Exgcd(d,p,x,y);k=(x*b%p+p)%p,j=find(k);        if(~j) return (LL)i*m+j+cnt;    }    return -1;}int main(){    LL a,b,p,ans;    while(a=in(),p=in(),b=in(),a||b||p){        ans=Exbsgs(a,b,p);        if(~ans) printf("%lld\n",ans);else puts("No Solution");    }    return 0;}
1 1
原创粉丝点击