转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents
题意:
给定newx, k, m, 方程
xk≡newx(mod m)
, 求模m下x的所有解
0≤newx,m,k≤1.5∗1015
m是素数。
思路:
素数一定存在原根,首先求出m的原根g
根据原根的性质,一定存在
1≤y≤m−1
使得
gy≡newx(mod m)
y可以通过大步小步算法来求,不会的可以看一下这道模板题
则
xk≡gy(mod m)
根据离散对数的性质可以得到
kloggx≡y(mod φ(m))
这里 φ(m) 是m的欧拉函数,由于m是素数, φ(m)=m−1
对于上面这个方程,即
kloggx−bφ(m)=y
即二元一次方程
ax−by=c
利用 扩展欧几里得算法可以求解
具体代码如下:
Result:Accepted
Memory: 12904K
Time : 46MS
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll g,y;
ll fac[20];//第i个因数
int cnt=0;//注意不要忘记初始化
int Case;
ll A,C,B;
ll mod_mul(ll x,ll n, ll mod)
{
ll res = 0;
while(n>0)
{
if(n&1) res = (res+x)%mod;
x = (x<<1)%mod;
n>>=1;
}
return res;
}
ll mod_pow(ll x,ll n, ll mod)
{
x%=mod;
ll res = 1;
while(n>0)
{
if(n&1) res = mod_mul(res,x,mod);
x = mod_mul(x,x,mod);
n>>=1;
}
return res;
}
const int HASH_MOD=987654;
ll key[HASH_MOD], val[HASH_MOD];
int head[HASH_MOD], Next[HASH_MOD];
struct Hash{
int tot;
void init(){
memset(head, -1, sizeof(head));
tot = 0;
}
ll insert(ll x, ll y){
int k = x % HASH_MOD;
key[tot] = x;
val[tot] = y;
Next[tot] = head[k];
head[k] = tot++;
}
ll find(ll x){
int k = x % HASH_MOD;
for(int i = head[k]; i != -1; i = Next[i])
if(key[i] == x)
return val[i];
return -1;
}
}hs;
ll log_mod(ll a, ll b, ll m){
hs.init();
ll s = ceil(sqrt(m + 0.5));
ll cur = 1;
for (int i = 0; i < s; ++i){
if(hs.find(cur)==-1) hs.insert(cur,i);
cur = cur * a % m;
}
ll v = mod_pow(a, (m - s - 1 + m) % m, m);
for(int i = 0; i < s; ++i){
ll tmp = hs.find(b);
if(tmp!=-1)
return s * i + tmp;
b=b*v%m;
}
return -1;
}
vector<ll> a;
bool g_test(ll g,ll p){
for(ll i=0;i<a.size();++i)
if(mod_pow(g,(p-1)/a[i],p)==1)
return 0;
return 1;
}
ll priroot(ll p)
{
a.clear();
ll tmp=p-1;
for(ll i=2;i<=tmp/i;++i)
if(tmp%i==0){
a.push_back(i);
while(tmp%i==0)
tmp/=i;
}
if(tmp!=1)
a.push_back(tmp);
ll g=1;
while(true){
if(g_test(g,p))
return g;
++g;
}
}
void exgcd(ll a, ll b, ll& d, ll& x, ll& y)
{
if(!b){ d = a; x = 1; y = 0;}
else{ exgcd(b, a%b, d, y, x); y -= a/b*x; }
}
ll d;
vector<ll> solve(ll a, ll b,ll c)
{
vector<ll> vec;
ll x,y;
exgcd(a, b, d, x, y);
if(!d || c%d)
return vec;
x *= c/d;
y *= c/d;
a /= d;
b /= d;
if(a<0) a=-a;
if(b<0) b=-b;
((x %= b) += b) %=b;//此时x+mb,y-ma都是解,m为自然数
((y %= a) += a) %=a;
for(int i=0;i<d;i++)
vec.push_back(mod_pow(g,x+i*b,C));
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
return vec;
}
int main()
{
vector<ll> vec;
while(~scanf("%lld%lld%lld",&A,&C,&B))
{
printf("case%d:\n",++Case);
g = priroot(C);
y = log_mod(g,B,C);
vec = solve(A,C-1,y);
if(vec.size()==0)puts("-1");
for(int i=0;i<vec.size();i++)
printf("%lld\n",vec[i]);
}
}