2242: [SDOI2011]计算器
2016-09-04 13:46
169 查看
2242: [SDOI2011]计算器
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3045 Solved: 1206
[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。
Sample Output
【样例输出1】2
1
2
【样例输出2】
2
1
0
HINT
Source
第一轮day1[Submit][Status][Discuss]
对于询问1,快速幂解决
对于询问2,扩展欧几里得解决
对于询问3,采用BSGS算法
询问y^x≡z(mod p)的最小非负整数解x,保证p为素数
令Sqrt = sqrt(p)
则y^x = (y^Sqrt)^i*y^j
枚举i,令T = (y^Sqrt)^i
则原式化为T*y^j≡z(mod p)
用扩展欧几里得求出y^j
hash查表。。。
如果p不是素数,可以用扩展BSGS
#include<iostream> #include<cstdio> #include<queue> #include<vector> #include<bitset> #include<algorithm> #include<cstring> #include<map> #include<stack> #include<set> #include<cmath> #include<ext/pb_ds/priority_queue.hpp> using namespace std; const int hash = 999983; typedef long long LL; int T,typ,top,s[hash],ha[hash],va[hash]; int ksm(LL x,int y,LL p) { LL ret = 1; for (; y; y >>= 1) { if (y & 1) ret = ret*x%p; x = x*x%p; } return ret; } LL gcd(LL a,LL b,LL &x,LL &y) { if (!b) { x = 1; y = 0; return a; } LL ret = gcd(b,a%b,x,y); LL tmp = x; x = y; y = tmp - y*(a/b); return ret; } LL GCD(LL a,LL b,LL z) { LL x,y; LL g = gcd(a,b,x,y); if (z % g != 0) return -1; x = x * z / g; if (x < 0) x = x % b + b; return x % b; } void hash_insert(int v,int mi) { int posi = v%hash; while (va[posi] != -1) { if (va[posi] == v) return; ++posi; } va[posi] = v; ha[posi] = mi; s[++top] = posi; } int hash_search(LL now) { int posi = now%hash; for (;;) { if (va[posi] == -1) return -1; if (va[posi] == now) return ha[posi]; ++posi; } } LL Baby_step(LL t,LL p,LL z,LL Sqrt) { LL now = 1; for (int i = 0; i <= Sqrt; i++) { LL x = GCD(now,p,z); if (x == -1) continue; int posi = hash_search(x%p); if (posi != -1) return i*Sqrt + posi; now = now*t%p; } return -1; } int main() { #ifdef DMC freopen("DMC.txt","r",stdin); #endif memset(va,-1,sizeof(va)); cin >> T >> typ; while (T--) { if (typ == 1) { int x,y,p; cin >> x >> y >> p; printf("%d\n",ksm(x,y,p)); } else if (typ == 2) { int y,z,p; LL x; cin >> y >> z >> p; x = GCD(y,p,z); if (x == -1) puts("Orz, I cannot find x!"); else cout << x << endl; } else { int y,z,p,Sqrt,t; LL x; cin >> y >> z >> p; Sqrt = sqrt(p); if (Sqrt * Sqrt < p) ++Sqrt; int now = 1; //top = 0; for (int i = 0; i <= Sqrt; i++) hash_insert(now,i),now = 1LL*now*y%p; t = ksm(y,Sqrt,p); x = Baby_step(t,p,z,Sqrt); if (x == -1) puts("Orz, I cannot find x!"); else cout << x << endl; while (top) va[s[top--]] = -1; } } return 0; }
相关文章推荐
- BZOJ2242 [SDOI2011]计算器
- bzoj 2242 [SDOI2011]计算器(数论知识)
- [bzoj2242][SDOI2011]计算器
- bzoj 2242: [SDOI2011]计算器 BSGS+快速幂+扩展欧几里德
- Bzoj2242 [SDOI2011]计算器
- 【BZOJ2242】[SDOI2011]计算器 BSGS
- BZOJ2242 [SDOI2011]计算器
- 【BZOJ】2242: [SDOI2011]计算器
- BZOJ-2242-计算器-SDOI2011-BSGS
- 【bzoj2242】[SDOI2011]计算器
- 【SDOI2011】【BZOJ2242】计算器
- BZOJ-2242-计算器-SDOI2011-BSGS
- BZOJ 2242: [SDOI2011]计算器
- 【数论】【快速幂】【扩展欧几里得】【BSGS算法】bzoj2242 [SDOI2011]计算器
- 【BZOJ2242】[SDOI2011]计算器 BSGS+exgcd+快速幂
- BZOJ 2242: [SDOI2011]计算器
- BZOJ2242 [SDOI2011]计算器 【BSGS】
- bzoj2242【sdoi2011】计算器
- 【bzoj2242】[SDOI2011]计算器 快速幂+exgcd+BSGS
- bzoj 2242 [sdoi2011]计算器