Description
已知数a,p,b,求满足a^x≡b(mod p)的最小自然数x。
Input
每个测试文件中最多包含100组测试数据。
每组数据中,每行包含3个正整数a,p,b。
当a=p=b=0时,表示测试数据读入完全。
Output
对于每组数据,输出一行。
如果无解,输出“No Solution”(不含引号),否则输出最小自然数解。
Sample Input
5 58 33
2 4 3
0 0 0
2 4 3
0 0 0
Sample Output
9
No Solution
No Solution
HINT
100%的数据,a,p,b≤1e9。
扩展bsgs
这题没规定p是质数,逆元就得用扩欧来做...
首先如果如果存在解x且gcd(a,p) != 1
那么把化为
把式子写成
令d = gcd(a,p)有
一直处理到gcd(a,p)为1,并且如果b不能整除d 即无解
此时得到
此时有
此时用一般的bsgs 处理,
令
即
考虑令
此时式子可化为
那么显然当时最优。
用map记录一下。
然后枚举t即可...注意p不一定为质数
的值需用exgcd处理
累死我了...
c++代码如下:
#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x; i <= y ;++ i)
#define repd(i,x,y) for(register int i = x; i >= y ; --i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
x = 0;char c;int sign = 1;
do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
x *= sign;
}
int a,p,b;
map<int,int>mp;
int gcd(int x,int y) { return !y ? x : gcd(y,x%y);}
int quick_pow(int x,int y,int p)
{
int ans = 1;
while(y)
{
if(y&1) ans = (ll)ans * x %p;
x = (ll)x * x % p;
y >>= 1;
}
return ans;
}
int ex_gcd(int a,int b,int&x,int&y)
{
if(!b) { x = 1; y = 0; return a; }
ex_gcd(b,a%b,y,x);
y -= a/b*x;
}
inline void ex_bsgs(int a,int p,int b)
{
a %= p;b %= p;
if(b == 1) return void(puts("0"));
int x,d,e = 1,cnt = 0;
while((d = gcd(a,p)) != 1)
{
if(b % d) return void(puts("No Solution"));
b /= d;p /= d;e = (ll)e * a/d%p;cnt++;
if(e == b) { return void(printf("%d\n",cnt)); }
}
int t = ceil((double)sqrt(p)),k;
ex_gcd(quick_pow(a,t,p),p,k,x);
k = (k%p+p)%p;
mp.clear();mp[e] = 0;
x = e;
rep(i,1,t - 1)
{
x = (ll)x * a % p;
if( !mp.count(x) ) mp[x] = i;
}
rep(i,0,t - 1)
{
if(mp.count(b)) return void(printf("%d\n",mp[b] + i*t + cnt));
b = (ll)b * k % p;
}
puts("No Solution");
}
int main()
{
while(1)
{
read(a);read(p);read(b);
if(!a && !p && !b) break;
if(p == 1) { puts("0");continue; }
ex_bsgs(a,p,b);
}
return 0;
}
补一份spoj:ac代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<iostream>
#include<cctype>
#include<algorithm>
#define rep(i,x,y) for(register int i = x; i <= y ;++ i)
#define repd(i,x,y) for(register int i = x; i >= y ; --i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
x = 0;char c;int sign = 1;
do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
x *= sign;
}
int a,p,b;
int gcd(int x,int y) { return !y ? x : gcd(y,x%y);}
int quick_pow(int x,int y,int p)
{
int ans = 1;
while(y)
{
if(y&1) ans = (ll)ans * x %p;
x = (ll)x * x % p;
y >>= 1;
}
return ans;
}
int ex_gcd(int a,int b,int&x,int&y)
{
if(!b) { x = 1; y = 0; return a; }
ex_gcd(b,a%b,y,x);
y -= a/b*x;
}
const int P = 999979,N = 1e5 + 50;
int head[1000000],z[N],tot;
int to[1000000],w[1000000],nxt[1000000],Tot;
inline void add(int x,int y,int val)
{
nxt[Tot] = head[x];
w[Tot] = val;
to[Tot] = y;
head[x] = Tot++;
}
inline int get(int x)
{
x = 1ll * x * 233 % P;
return x;
}
inline int check(int x)
{
int ans = -1;
int y = get(x);
for(register int i = head[y];~i;i=nxt[i])
if(to[i] == x)
{
if(ans == -1) ans = w[i];
else ans = min(ans,w[i]);
}
return ans;
}
inline void ex_bsgs(int a,int p,int b)
{
a %= p;b %= p;
if(b == 1) return void(puts("0"));
int x,d,e = 1,cnt = 0;
while((d = gcd(a,p)) != 1)
{
if(b % d) return void(puts("no solution"));
b /= d;p /= d;e = (ll)e * a/d%p;cnt++;
if(e == b) { return void(printf("%d\n",cnt)); }
}
int t = ceil((double)sqrt(p)),k;
ex_gcd(quick_pow(a,t,p),p,k,x);
k = (k%p+p)%p;
x = e;
int u = get(e);
add(u,e,0);z[++tot] = u;
rep(i,1,t - 1)
{
x = (ll)x * a % p;
int y = get(x);
add(y,x,i); z[++tot] = y;
}
rep(i,0,t - 1)
{
int z;
if((z = check(b)) != -1) return void(printf("%d\n",z + i*t + cnt));
b = (ll)b * k % p;
}
puts("no solution");
}
int main()
{
memset(head,-1,sizeof head);
while(scanf("%d%d%d",&p,&a,&b) != EOF)
{
if(p == 1) { puts("0");continue; }
ex_bsgs(a,p,b);
rep(i,1,tot) head[z[i]] = -1; tot = 0;Tot = 0;
}
return 0;
}