hdu 3930 N次剩余
2017-08-12 21:52
232 查看
转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents
0≤newx,m,k≤1.5∗1015 m是素数。
根据原根的性质,一定存在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
题意:
给定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]); } }
相关文章推荐
- N次剩余 (hdu 3930)
- HDU 3223 Decrypt Messages 【N次剩余+模拟】
- hdu 3930 Broot 二次剩余
- HDU 6128 Inverse of sum(二次剩余)
- hdu 3930 X^N=a(mod) p 求X
- HDU 4542:小明系列故事——未知剩余系
- 【中国剩余定理】POJ 1006 & HDU 1370 Biorhythms
- hdu 5668 中国剩余定理(模版)
- HDU 5768 Lucky7 数论 中国剩余定理
- HDU 1788 Chinese remainder theorem again 中国剩余定理
- HDU 5446 Unknown Treasure Lucas+中国剩余定理+按位乘
- 一些关于中国剩余定理的数论题(POJ 2891/HDU 3579/HDU 1573/HDU 1930)
- (hdu 2.3.2)Exponentiation(大数:求R的n次幂)
- hdu 5446(中国剩余+lucas+按位乘)
- N次剩余(详解+例题+代码)
- hdu_1370Biorhythms(互素的中国剩余定理)
- hdu 5088 高斯消元n堆石子取k堆石子使剩余异或值为0
- hdu 3930 X^N=a(mod) p 求X
- 【hdu】3430 Shuffling【中国剩余定理】
- hdu 1370 Biorhythms 中国剩余定理的应用 and 枚举方法