題目連結
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22207
題目大意
已知 k、y、p ,求 xk≡y(modp) 的所有可行解
思路
首先,我們求出 modp 的原根 g 。
不妨設gq≡y(modp), q 可以通過大步小步算法求得。
由于在1≤x<p時, modp 意義下所有的數字均可以用 g 的幂次表示。是以一定存在等式gi≡k(modp−1)。這個可以通過中國剩餘定理找出所有的可行解。
—————–以下來閑扯一下大步小步算法——————-
大步小步算法看上去非常的暴力,個人認為其思路就是基于分塊思想。假設已知 x、y、p ,求 xk≡y(modp)的k ,那麼首先我們要對于所有的 i≤p√ ,在map中記錄下 xi 對應于 i 的映射。然後維護一個值xt,初始時 t=0 ,每次 t+=p√ ,若在map中能夠查找到 yxt(m−2) (這個操作複雜度隻是對數),那麼就找到了答案, k=t+mp[yxt(m−2)] , mp[yxt(m−2)]=yxt(m−2)在 map中映射的幂
代碼
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
using namespace std;
typedef long long int LL;
vector<LL>divisor,ans;
LL extGCD(LL a,LL b,LL &x,LL &y)
{
if(!b)
{
x=;
y=;
return a;
}
LL gcd=extGCD(b,a%b,x,y);
LL tmp=x;
x=y;
y=tmp-a/b*y;
return gcd;
}
LL fastPow(LL base,LL pow,LL mod)
{
LL ans=;
while(pow)
{
if(pow&) ans=(ans*base)%mod;
base=(base*base)%mod;
pow>>=;
}
return ans;
}
bool g_test(LL g,LL p) //檢查g是否是mod p的原根
{
for(int i=;i<(int)divisor.size();i++)
if(fastPow(g,(p-)/divisor[i],p)==)
return false;
return true;
}
LL PrimitiveRoot(LL p) //求mod p的原根
{
divisor.clear();
LL tmp=p-;
for(LL i=;i*i<=tmp;i++)
{
if(tmp%i==)
{
divisor.push_back(i);
while(tmp%i==) tmp/=i;
}
}
if(tmp!=) divisor.push_back(tmp);
LL g=; //爆枚原根g
while(++g)
if(g_test(g,p))
return g;
return -;
}
LL DiscreteLog(LL x,LL n,LL m) //求離散對數,x^y=n(mod m),求y
{
map<LL,LL>table; //一個有序表
LL sqrtm=(LL)(sqrt(m)+);
LL tmp=; //x^i=tmp
for(int i=;i<sqrtm;i++)
{
table[tmp]=i;
tmp=tmp*x%m;
}
LL step=tmp; //t=x^sqrt(m)
tmp=;
for(int i=;i<sqrtm;i++)
{
LL d=n*fastPow(tmp,m-,m)%m;
if(table.count(d))
return i*sqrtm+table[d];
tmp=tmp*step%m;
}
return -;
}
void CRT(LL a,LL b,LL n) //ax=b(mod n)
{
LL x,y,gcd;
gcd=extGCD(a,n,x,y);
if(b%gcd==) //有解
{
x=(x%n+n)%n;
ans.push_back(x*(b/gcd)%(n/gcd));
for(LL i=;i<gcd;i++)
ans.push_back((ans[]+i*n/gcd)%n);
}
}
int main()
{
LL a,p,g,q,k;
while(scanf("%lld%lld%lld",&p,&k,&a)!=EOF) //x^k=a(mod p)
{
if(!a) //a=0要特判,x隻能為0
{
printf("1\n0\n");
continue;
}
g=PrimitiveRoot(p); //g=mod p的原根
q=DiscreteLog(g,a,p); //g^q=a(mod p)
CRT(k,q,p-); //問題變為kx=q(mod p-1)的所有正整數解
for(int i=;i<(int)ans.size();i++)
ans[i]=fastPow(g,ans[i],p); //ans[i]=g^x mod p
sort(ans.begin(),ans.end());
printf("%d\n",(int)ans.size());
for(int i=;i<(int)ans.size();i++) printf("%lld\n",ans[i]);
}
return ;
}