首页 > 代码库 > SDOI2011计算器
SDOI2011计算器
2242: [SDOI2011]计算器
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1274 Solved: 491
[Submit][Status]
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
题解:这一题考了几个基本的数论算法,1不用多说,2扩展欧几里得求逆元也不多说。
至于3吗,我做这题以前是不知道的,后来才明白这玩意叫做离散对数,查了资料学会了这个东西(我有多弱!!!)
求a^x=b(mod n) 的最小的x的算法(shank的大步小步算法)
令m为n^0.5
我们可以求出a^0,a^1,a^2...a^(m-1) mod n 的值,记为e0,e1,e2,em-1,用map将它们存下来(为了方便之后查询,对每个ei存下它对应的最小的下标i)
求出a^m模n的逆元v
那么如果a^(k*m+0),a^(k*m+1),a^(k*m+2)...a^(k*m+m-1)模m余b(k从0到m-1),等价于
a^0=b*(v^(k*m))(mod n)
a^1=b*(v^(k*m))(mod n)
...
a*(m-1)=b*(v^(k*m))(mod n)
这样我们只要枚举k,然后在map中查询b*(v^(k*m))是否存在,若存在,用它在map中对应的i得到答案k*m+i。
这样做的时间复杂度是O(n^0.5log(n))考虑到题目数据最多十组,应该不会超时。
1 #include <iostream> 2 #include <cmath> 3 #include <map> 4 using namespace std; 5 typedef long long LL; 6 int T,k; 7 LL mul_mod(LL a,LL b,LL n){ 8 return a*b%n; 9 }10 LL pow_mod(LL a,LL p,LL n){11 if (p==0) return 1;12 LL ans=pow_mod(a,p/2,n);13 ans=ans*ans%n;14 if (p&1) ans=ans*a%n;15 return ans;16 }17 LL gcd(LL a,LL b){18 return (b==0)?a:(gcd(b,a%b));19 }20 void exgcd(LL a,LL b,LL &x,LL &y){21 if (b==0) {x=1;y=0;return ;}22 else {exgcd(b,a%b,y,x);y=y-(a/b)*x;}23 }24 LL inv(LL a,LL n){25 LL x,y;26 exgcd(a,n,x,y);27 return (x+n)%n;28 }29 LL log_mod(LL a,LL b,LL n){30 LL m,v,e=1,i;31 m=((int)sqrt(n)) +1;32 if (gcd(a,n)!=1) return -1;33 v=inv(pow_mod(a,m,n),n);34 map <int,int> x;35 x[1]=0;36 for (i=1;i<m;i++){37 e=mul_mod(e,a,n);38 if (!x.count(e)) x[e]=i;39 }40 for (i=0;i<m;i++){41 if (x.count(b)) return i*m+x[b];42 b=mul_mod(b,v,n);43 }44 return -1;45 }46 int main(){47 cin>>T>>k;48 LL y,z,p,t;49 while (T--){50 cin>>y>>z>>p;51 switch (k) {52 case 1:53 cout<<pow_mod(y,z,p)<<endl; break;54 case 2:{55 LL g=gcd(y,p);56 if (z%g!=0) cout<<"Orz, I cannot find x!"<<endl;57 else {58 y/=g;p/=g;z/=g;59 cout<<mul_mod(inv(y,p),z%p,p)<<endl;60 }61 break;62 }63 case 3:if ((t=log_mod(y,z,p))==-1) cout<<"Orz, I cannot find x!"<<endl;64 else cout<<t<<endl;65 break;66 }67 }68 return 0;69 }
SDOI2011计算器
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。