BZOJ 2242: [SDOI2011]计算器
Submit: 4336 Solved: 1672
[Submit][Status][Discuss]
Description
你被要求设计一个计算器完成以下三项任务:
1、给定y,z,p,计算Y^Z Mod P 的值;
2、给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数;
3、给定y,z,p,计算满足Y^x ≡ Z ( mod P)的最小非负整数。
Input
输入包含多组数据。
第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。
以下行每行包含三个正整数y,z,p,描述一个询问。
Output
对于每个询问,输出一行答案。对于询问类型2和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”,注意逗号与“I”之间有一个空格。
Sample Input
【样例输入1】
3 1
2 1 3
2 2 3
2 3 3
【样例输入2】
3 2
2 1 3
2 2 3
2 3 3
【数据规模和约定】
对于100%的数据,1<=y,z,p<=10^9,为质数,1<=T<=10。
3 1
2 1 3
2 2 3
2 3 3
【样例输入2】
3 2
2 1 3
2 2 3
2 3 3
【数据规模和约定】
对于100%的数据,1<=y,z,p<=10^9,为质数,1<=T<=10。
Sample Output
【样例输出1】
2
1
2
【样例输出2】
2
1
0
2
1
2
【样例输出2】
2
1
0
HINT
Source
第一问快速幂
第二问exgcd
第三问BSGS,好麻烦我就先略
为啥叫baby step giant step,我其实不是很懂
求\(y^x = z(mod~p)\)设\(x=km+i\)\[y^{km}*y^i\equiv z\]\(y^i\equiv z*ine(y^{km})\)(逆元)
用费马小定理显然可得\(ine(y^m)\equiv y^{p-1-m}\)设其为T
\[ine(y^{km})\equiv ine(y^{(k-1)m})*T\]
把\[y^i(0<=i<=m)\]放入hash或者map
然后枚举k,查询\[z*ine(y^{km})\]
显然m取\(\sqrt p\)复杂度比较优秀。。
解释部分转自黄学长
#include <ctype.h> #include <cstdio> #include <cmath> #include <map> using namespace std; typedef long long LL; map<LL,int>q; void read(int &x) { x=0;bool f=0; register char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=1; for(; isdigit(ch);ch=getchar()) x=x*10+ch-'0'; x=f?(~x)+1:x; } inline LL ksm(int a,int b,int c) { LL base=a,r=1%c; while(b) { if(b&1) r=(r*base)%c; base=(base*base)%c; b>>=1; } return r; } int gcd(int a,int b) {return a%b==0?b:gcd(b,a%b);} void exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1;y=0; return; } exgcd(b,a%b,x,y); int tmp=x; x=y; y=tmp-(a/b)*y; } int T,L; int main() { read(T); read(L); for(int y,z,p;T--;) { read(y); read(z); read(p); switch(L) { case 1: { printf("%d\n",ksm(y,z,p)); break; } case 2: { int m,n; p=-p; int k=gcd(y,p); if(z%k) printf("Orz, I cannot find x!\n"); else { y/=k;z/=k;p/=k; exgcd(y,p,m,n); m=(LL)m*z%p; for(;m<0;m+=p); printf("%d\n",m); } break; } case 3: { if(y%p==0&&z==0) printf("1\n"); else if(y%p==0) printf("Orz, I cannot find x!\n"); else { q.clear(); bool flag=false; LL t=1,m=ceil(sqrt(p)); q[1]=m+1; for(LL i=1;i<m;i++) { t=t*y%p; if(!q[t]) q[t]=i; } t=ksm(y,p-m-1,p);LL in=1; for(LL k=0;k<m;k++) { int ans=z*in%p; if(q[ans]) { int v=q[ans]; if(v==m+1) v=0; printf("%lld\n",k*m+v); flag=true; break; } in=in*t%p; } if(!flag) printf("Orz, I cannot find x!\n"); } break; } } } return 0; }
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。