题目链接:http://www.spoj.com/problems/MOD/ (POJ 3243双倍经验)
Description
Given 3 positive integers x, y and z, you can find k = xy%z easily, by fast power-modulo algorithm. Now your task is the inverse of this algorithm. Given 3 positive integers x, z and k, find the smallest non-negative integer y, such that k%z = xy%z.
[题目大意]求最小的y使得k ≡ xy (mod z)
Input
About 600 test cases.
Each test case contains one line with 3 integers x, z and k.(1<= x, z, k <=109)
Input terminates by three zeroes. (以三个0结束输入)
Output
For each test case, output one line with the answer, or “No Solution”(without quotes) if such an integer doesn’t exist.
Sample Input
5 58 33
2 4 3
0 0 0
Sample Output
9
No Solution
Solution
此题为扩展BSGS(Baby Steps Giant Steps)模板题
普通BSGS
对于
Ax≡B(modC)
令m=
⌊c√⌋+1
则原式可变为
Ai∗m−j
,其中i,j
∈[1,m]
①
移项后得
Ai∗m≡B∗Aj(modC)
②
从1~m枚举j,把
B∗AjmodC
扔进哈希表里
然后从1~m枚举i,看看
Ai∗m
在不在哈希表里。如果在,则
i∗m
-
j
即为答案;如果枚举完所有i后仍没找到过,则无解
以上是普通BSGS的流程,只适用于gcd(A,C)=1的情况,这是因为在从①变化至②的过程中,如果
扩展BSGS
Ax≡B(modC)
由取模定义可得
Ax=k∗C+B
令
g=gcd(A,C)
,则有
Axg=k∗Cg+Bg
Axg≡Bg(modCg)
Ag∗Ax−1≡Bg(modCg
)
如果g不为B的因数的话,显然无解
另
B′=Bg
,
C′=Cg
,重复执行以上消掉gcd的步骤,直到
gcd(A,C′)=1
这时,原式已变为
D∗Ax−cnt≡B′(modC′)
cnt为执行了消除gcd步骤的次数,D为历次
Ag
之积
现在执行普通的BSGS,将结果加上cnt即为答案
不过,有一点要注意,如果答案在 [0,cnt - 1] 内,BSGS可能会给出错误的答案。此时只需要先暴力扫一遍答案是否可能在 [0,cnt - 1] 内就行了,因为cnt最多只能到log(n),时间完全不虚
Code
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 100000
#define mod 99991
#define foru(i,l,r) for (int i=l; i<=r; i++)
#define setmem(a,x) memset(a,x,sizeof(a))
typedef long long LL;
int val[N],id[N],stk[N],top;
LL x,y,g;
int gethash(int x) {return x%mod;}
void insert(int x, int y)
{
int h=gethash(x);
while (val[h]!=-1&&val[h]!=x) h=(h+1)%mod;
val[h]=x, id[h]=y;
stk[++top]=h;
}
int get(int x)
{
int h=gethash(x);
while (val[h]!=-1&&val[h]!=x) h=(h+1)%mod;
if (val[h]==-1) return -1;
return id[h];
}
void clear()
{
for (; top; top--) val[stk[top]]=-1;
}
int gcd(int a, int b)
{
return !b? a: gcd(b,a%b);
}
int bsgs(int A, int B, int C, LL D)
{
LL m=ceil(sqrt(C)), am=1;
clear();
foru(i,1,m)
{
am=(am*A)%C;
insert(am*B%C,i);
}
foru(i,1,m)
{
D=D*am%C;
int j=get(D);
if (j!=-1) return i*m-j;
}
return -1;
}
int exbsbg(int a, int b, int c)
{
LL x=1%c, d=1, g, cnt=0;//c=1的情况要小心
foru(i,0,100)
{
if (x==b) return i;
x=x*a%c;
}
while ((g=gcd(a,c))!=1)
{
if (b%g!=0) return -1;
b/=g, c/=g;
d=d*(a/g)%c, cnt++;
}
int ans=bsgs(a,b,c,d);
if (ans==-1) return -1;
else return ans+cnt;
}
int main()
{
setmem(val,-1);
int x,z,k;
while (scanf("%d%d%d",&x,&z,&k)!=EOF&&(x|z|k))
{
int ans=exbsbg(x%z,k%z,z);
if (ans==-1) puts("No Solution");
else printf("%d\n",ans);
}
return 0;
}