hdu 3930(BSGS+原根+扩展欧几里得)
2017-09-22 09:40
225 查看
先介绍一篇关于原根与离散对数的优秀博文:http://blog.csdn.net/smilewsw/article/details/47659793
传送门
题解:
对于X^A = B (mod C)
1.求出B关于C的原根root
2.用BSGS求出满足root^cc = B (mod C)的cc
3.由原根性质,root^x=X,所以原方程转化为求root^(xA) = root^cc (mod C) ①,再由阶的性质:”若(a,m)=1,m>0,则a^i=a^j(mod m),当且仅当i=j(mod ordm(a)),其中i,j是非负整数“,而此处ordm(root)=φ(C)=C-1。于是①式转化为xA = cc (mod C-1)②,求出一个最小x0后,所有的x=x0+k*(C-1)/gcd(C-1,A)的都满足②式。而当k=gcd(C-1,A)时,root^x mod C的值出现循环,所以求gcd(C-1,A)个x即可,最后快速幂一下就好。
关于BSGS的模板要鸣谢:idy002学长
作为一名OIer我在此郑重承诺:以后long long都用cin,cout。。。
传送门
题解:
对于X^A = B (mod C)
1.求出B关于C的原根root
2.用BSGS求出满足root^cc = B (mod C)的cc
3.由原根性质,root^x=X,所以原方程转化为求root^(xA) = root^cc (mod C) ①,再由阶的性质:”若(a,m)=1,m>0,则a^i=a^j(mod m),当且仅当i=j(mod ordm(a)),其中i,j是非负整数“,而此处ordm(root)=φ(C)=C-1。于是①式转化为xA = cc (mod C-1)②,求出一个最小x0后,所有的x=x0+k*(C-1)/gcd(C-1,A)的都满足②式。而当k=gcd(C-1,A)时,root^x mod C的值出现循环,所以求gcd(C-1,A)个x即可,最后快速幂一下就好。
关于BSGS的模板要鸣谢:idy002学长
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const int mop=1e7+4; int prime[mop/10],tot=0,cnt; ll temp[mop],ans[mop],A,B,C; bool vis[mop]; inline void linear_shaker() { memset(vis,false,sizeof(vis)); for (register int i=2;i<mop;++i) { if (!vis[i]) prime[++tot]=i; for (int j=1;j<=tot&&i*prime[j]<mop;++j) { vis[i*prime[j]]=true; if (i%prime[j]==0) break; } } } inline void divide(ll a) { cnt=0; int t=(int)sqrt(1.0+a); for (int i=1;prime[i]<=t;++i) { if (a%prime[i]==0) temp[++cnt]=prime[i]; while (a%prime[i]==0) a/=prime[i]; } if (a>1) temp[++cnt]=a; } inline ll mult(ll x,ll y,ll MOD) { x%=MOD,y%=MOD; return ((x*y-(ll)(((long double)x*y+0.5)/MOD)*MOD)%MOD+MOD)%MOD; } inline ll fpow(ll a,ll b,ll MOD) { ll ret=1; while (b) { if (b&1) ret=mult(ret,a,MOD); b>>=1,a=mult(a,a,MOD); } return ret; } inline ll broot(ll p) { divide(p-1); for (int g=2;;++g) { bool flag=true; for (int i=1;i<=cnt;++i) if (fpow(g,(p-1)/temp[i],p)==1) { flag=false; break; } if (flag) return g; } } inline ll gcd(ll a,ll b) { return !b?a:gcd(b,a%b); } inline ll exgcd(ll a,ll b,ll &x,ll &y) { if (!b) { x=1,y=0; return a; } ll d=exgcd(b,a%b,y,x); y-=(a/b)*x; return d; } inline ll inv(ll a,ll p) { return fpow(a,p-2,p); } struct Hash_{ int head[mop],last[mop],etot; ll dest[mop][2]; void init(){ memset(head,0,sizeof(head)); etot=0; } void add(ll a,ll b){ int key=a%mop; for(int t=head[key];t;t=last[t]) if(dest[t][0]==a) return; last[++etot]=head[key]; dest[etot][0]=a; dest[etot][1]=b; head[key]=etot; } ll query(int a){ int key=a%mop; for(int t=head[key];t;t=last[t]) if(dest[t][0]==a) return dest[t][1]; return -1; } }has; inline ll BSGS(ll g, ll a,ll p){ if (g%p==0) return -1; has.init(); ll m=(ll)ceil(sqrt(a))+1; ll cur=1; for(register int i=0;i<m;++i,cur=mult(cur,g,p)){ if(cur==a) return i; has.add(cur,i); } ll base=inv(cur,p); cur=mult(base,a,p); for(register int i=m;i<=p-1;i+=m,cur=mult(cur,base,p)) { ll j=has.query(cur); if(~j) return j+i; } return -1; } inline void work(ll A,ll B,ll C) { ll root=broot(C); ll cc=BSGS(root,B,C); ll bb=C-1; ll d=gcd(A,bb); if (cc%d) { cout<<"-1\n"; return ; } ll x,y; d=exgcd(A,bb,x,y); bb/=d,cc/=d; ans[0]=mult(x,cc,bb); for (int i=1;i<d;++i) ans[i]=ans[i-1]+bb; for (int i=0;i<d;++i) ans[i]=fpow(root,ans[i],C); sort(ans,ans+d); for (int i=0;i<d;++i) cout<<ans[i]<<endl; } int main() { // freopen("hdu 3930.in","r",stdin); ios::sync_with_stdio(false); linear_shaker(); int kase=0; while (cin>>A>>C>>B) { cout<<"case"<<++kase<<":\n"; work(A,B,C); } return 0; }
作为一名OIer我在此郑重承诺:以后long long都用cin,cout。。。
相关文章推荐
- hdu 5377 Root 原根+离散对数+扩展欧几里得
- hdu_1576A/B(扩展欧几里得求逆元)
- HDU 1576 A/B (逆元求扩展欧几里得)
- hdu_2669_扩展欧几里得_first_blood
- HDU 1576 A/B (扩展欧几里得)
- 【A/B%m+扩展欧几里得】hdu 1576 A/B
- 原根(扩展欧几里得+欧拉函数)
- hdu - 2669 - Romantic(扩展欧几里得)
- hdu 2669 扩展欧几里得
- HDU1576 A/B (扩展欧几里得求逆元)
- 【HDU】2669 - Romantic(扩展欧几里得)
- hdu 3240 卡特兰数+质因数分解+扩展欧几里得求乘法逆元
- 中国剩余定理+扩展欧几里得求逆元 hdu 1006
- HDU 2669 Romantic【扩展欧几里得板子题】
- hdu 1576 A/B(扩展欧几里得)
- Root(hdu5777+扩展欧几里得+原根)2015 Multi-University Training Contest 7
- hdu1222(扩展欧几里得)
- hdu 1576 A/B(扩展欧几里得)
- hdu 1576 A/B(扩展欧几里得)
- HDU 1576 A/B 暴力也能过。扩展欧几里得