P2485 [SDOI2011]计算器
题目描述
你被要求设计一个计算器完成以下三项任务:
1、给定y、z、p,计算y^z mod p 的值;
2、给定y、z、p,计算满足xy ≡z(mod p)的最小非负整数x;
3、给定y、z、p,计算满足y^x ≡z(mod p)的最小非负整数x。
为了拿到奖品,全力以赴吧!
输入输出格式
输入格式:
输入文件calc.in 包含多组数据。
第一行包含两个正整数T、L,分别表示数据组数和询问类型(对于一个测试点内的所有数
据,询问类型相同)。
以下T 行每行包含三个正整数y、z、p,描述一个询问。
输出格式:
输出文件calc.out 包括T 行.
对于每个询问,输出一行答案。
对于询问类型2 和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”。
输入输出样例
输入样例#1:
3 1 2 1 3 2 2 3 2 3 3
输出样例#1:
2 1 2
输入样例#2:
3 2 2 1 3 2 2 3 2 3 3
输出样例#2:
2 1 0
输入样例#3:
4 3 2 1 3 2 2 3 2 3 3 2 4 3
输出样例#3:
0 1 Orz, I cannot find x! 0
说明
分析
三个模板,
- 快速幂,
- 求yx=z(mod p),转化成,yx-kp = z;可以用扩展欧几里得求解,并且要求z%gcd(y,p)!=0,(扩展欧几里得求ax+by=c:http://www.cnblogs.com/MashiroSky/p/5912977.html), 补充:因为p是质数,所以可以用费马小定理, p是质数,y与p互质,所以y有逆元,x=y^(-1)*z,y^(-1)=y^(p-2),因为0没有逆元,所以只有y=0时无解
- bsgs
注意,int与longlong类型,结尾的换行符
code
1 #include<iostream> 2 #include<cstdio> 3 #include<map> 4 #include<cmath> 5 6 using namespace std; 7 typedef long long LL; 8 map<int,int>mp; 9 10 int ksm(int a,int p,int mod) 11 { 12 int now = 1; 13 while (p) 14 { 15 if (p&1) 16 now = 1ll*now*a%mod; 17 a = 1ll*a*a%mod; 18 p = p>>1; 19 } 20 return now; 21 } 22 int exgcd(int a,int b,int &x,int &y) 23 { 24 if (b==0) 25 { 26 x = 1, y = 0; 27 return a; 28 } 29 int r = exgcd(b,a%b,x,y); 30 int t = x; 31 x = y; 32 y = t-(a/b)*y; 33 return r; 34 } 35 void bsgs(int a,int b,int p) 36 { 37 int m,t,ans,now; 38 if (a%p==0&&b==0) 39 { 40 printf("1\n");return ; 41 } 42 if (a%p==0) 43 { 44 printf("Orz, I cannot find x!\n");return ; 45 } 46 mp.clear(); 47 m = ceil(sqrt(p)); 48 now = b%p; 49 mp[now] = 0; 50 for (int i=1; i<=m; ++i) 51 { 52 now = (1ll*now*a)%p; 53 mp[now] = i; 54 } 55 t = ksm(a,m,p); 56 now = 1; 57 for (int i=1; i<=m; ++i) 58 { 59 now = (1ll*now*t)%p; 60 if (mp[now]) 61 { 62 ans = i*m-mp[now]; 63 printf("%d\n",(ans%p+p)%p); 64 return ; 65 } 66 } 67 printf("Orz, I cannot find x!\n"); 68 } 69 int main() 70 { 71 int t,k,a,b,c; 72 scanf("%d%d",&t,&k); 73 if (k==1) 74 { 75 for (int i=1; i<=t; ++i) 76 scanf("%d%d%d",&a,&b,&c),printf("%d\n",ksm(a,b,c)); 77 } 78 else if (k==2) 79 { 80 int x,y; 81 for (int i=1; i<=t; ++i) 82 { 83 scanf("%d%d%d",&a,&b,&c); 84 int d = exgcd(a,c,x,y); 85 if (b%d!=0) printf("Orz, I cannot find x!\n"); //换行符 86 else 87 { 88 x = 1ll*x*(b/d)%c; 89 x = (x%(c/d)+c/d)%(c/d); 90 printf("%d\n",x); 91 } 92 } 93 } 94 else 95 { 96 for (int i=1; i<=t; ++i) 97 scanf("%d%d%d",&a,&b,&c),bsgs(a,b,c); 98 } 99 return 0; 100 }