这题的主要难点在于第三问该如何解决
于是就要知道BSGS是怎样的一种方法了
首先BSGS是meet in the middle的一种(戳下面看)
http://m.blog.csdn.net/blog/zentropy/11200099
看完链接后再看以下内容
---------------------------------------------------------------------------------------------------------------------
对于一个质数p 我们由费马小定理知道y^xmodp最多(p-1)次便是一个循环节
因此如果有解 x一定在0到p-1中
所以我们只需知道x取0到p-1是否有解即可
根据meet in the middle 的思想 令m=sqrt(p-1)
那么我们仅需先求出 0~m-1(如果有解这里就退出)
然后再求出 m,2m,3m……nm(nm<=p-1)
分别询问y^(0~m-1)中是否有和y^km乘起来modp等于z的
然而显然我们这个操作直接做的话 是sqrt(n)*sqrt(n)=n的
所以学过逆元怎么求了之后可以将y^km modp意义下的逆元与z相乘
然后再询问y^(0~m-1)中有没有与它相等的即可
这样去做就是sqrt(n)*hash的复杂度
有手动hash技巧的话 hash复杂度可以看做1
比较懒的话 直接用map来hash就是log(n)
#include <bits/stdc++.h> using namespace std; map<int,int> mp; int solve1(int x,int y,int mod) { long long t=x,re=1; while(y) { if(y&1) re=re*t%mod; t=t*t%mod; y>>=1; } return (int)re; } int exgcd(int a,int b,int &x,int &y) { if(!b) { x=1; y=0; return a; } int t,d; d=exgcd(b,a%b,x,y); t=x; x=y; y=t-(a/b)*x; return d; } void solve2(int y,int z,int p) { int x,yy; int d=exgcd(y,p,x,yy); if(z%d) { puts("Orz, I cannot find x!"); return; } x=(long long)x*(z/d)%p; x=(x<0?x+p:x); printf("%d\n",x); } bool solve3(int y,int z,int p) { // if(z>=p) // return 0; y%=p; if(!y) { if(z) return 0; puts("1"); return 1; } mp.clear(); int m=ceil(sqrt(p-1)); long long t=1; for(int i=0;i<m;++i) { if(t==z) { printf("%d\n",i); return 1; } if(!mp[t]) mp[t]=i+1; else return 0; t=t*y%p; } int inv=solve1(y,p-1-m,p); t=z; for(int i=m;i<=p-2;i+=m) { t=t*inv%p; if(mp[t]) { printf("%d\n",i+mp[t]-1); return 1; } } return 0; } int main() { int t,ca,y,z,p; scanf("%d%d",&t,&ca); while(t--) { scanf("%d%d%d",&y,&z,&p); if(ca==1) printf("%d\n",solve1(y,z,p)); else if(ca==2) solve2(y,z,p); else if(ca==3) if(!solve3(y,z,p)) puts("Orz, I cannot find x!"); } return 0; }
时间: 2024-10-10 12:30:21