2242: [SDOI2011]计算器
Time Limit: 10 Sec Memory Limit: 512 MB Submit: 3419 Solved: 1341 [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,p为质数,1<=T<=10。 Sample Output
【样例输出1】 2 1 2 【样例输出2】 2 1 0
数学の特定のテ-マは本当に恐ろしいquq… 这个题的话能算是一个综合题吧,三个操作对应着不同的算法。 对于第一个操作,比较简单,快速幂。 对于第二个操作,可以选择用扩展欧几里得解这个同余方程。但是我们注意到p为质数,可以使用费马小定理求解。首先考虑有没有解,如果y%p==0而z%p!=0的话,很显然Orz(这时无论x等于多少左边余数都为0)。之后我们用费马小定理求解,我就不讲了因为我也不会 我们可以用BSGS/离散对数算法(我会告诉你我一个也不会?)。稍微介绍一下BSGS算法的思路。 网上的许多题解中,是将 (摘自hzwer)
但是这道题可以使用另一种方法稍作简化,可以省去求逆元的步骤(你tm不会玩逆元就直说!!!)。 我们可以设
唔…这个奇妙的方法我是真的没懂,有没有神犇愿意给我讲一讲quq…
#include <cstdio>#include <algorithm>#include <map>#include <cmath>using namespace std;typedef long long LL;LL x,y,p,m,z;int T,flag;map <LL,LL> ma;LL power(LL b,LL p,LL k){ LL ans = 1; while(p){ if(p & 1) ans = (ans*b)%k; b = (b*b)%k; p >>= 1; } return ans;}void Bsgs(LL y,LL z,LL p){ int flag = 0; if(y == 0 && z == 0) {puts("1");return;} if(y == 0 && z != 0) {puts("Orz, I cannot find x!");return;} ma.clear(); LL tmp = 0,m=sqrt(p); for(LL i=0;i<=m;i++){ if(i == 0) {tmp = z%p;ma[tmp]=i;continue;} tmp = (tmp*y)%p; ma[tmp] = i; } LL t = power(y,m,p); tmp = 1; for(LL i=1;i*i<=p;i++){ tmp = (tmp*t)%p; if(ma[tmp]){ LL ans = (i*m)-ma[tmp]; PRintf("%lld/n",(ans%p+p)%p); flag = 1; break; } } if(!flag) puts("Orz, I cannot find x!");}int main(){ scanf("%d%d",&T,&flag); while( T-- ){ scanf("%lld%lld%lld",&y,&z,&p); y %= p; if(flag == 1) printf("%lld/n",power(y,z,p)); if(flag == 2){ z %= p; if(y==0 && z!=0) puts("Orz, I cannot find x!"); else printf("%lld/n",((z%p)*power(y,p-2,p))%p); } if(flag == 3) Bsgs(y,z,p); } return 0;}新闻热点
疑难解答