您的位置:首页 > 其它

hdu 3930 N次剩余

2017-08-12 21:52 232 查看
转载请注明出处,谢谢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]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: