[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、K,分别表示数据组数和询问类型(对于一个测试点内的所有数
据,询问类型相同)。
以下T 行每行包含三个正整数y、z、p,描述一个询问。
输出格式:输出文件calc.out 包括T 行.
对于每个询问,输出一行答案。
对于询问类型2 和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”。
输入输出样例
说明
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<map> #define ll long long using namespace std; int T,k; ll a,z,p; map<ll,int>ha; ll pow(ll a,ll x) { ll ans=1; while(x) { if(x&1)ans=(ans*a)%p; a=(a*a)%p; x>>=1; } return ans%p; } ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; } ll exgcd(ll a,ll b,ll &x,ll &y) { ll d=a; if(!b)x=1,y=0; else d=exgcd(b,a%b,y,x),y-=(a/b)*x; return d; } ll get(ll a,ll b) { ll x=0,y=0; ll d=exgcd(a,b,x,y); if(z%d)return -1; x*=(z/d); return (x%b+b)%b; } ll exbsgs(int a,int b,int x) { ha.clear(); a%=x,b%=x;ll m=ceil(sqrt((double)x)); if(b==1)return 0; ll tmp=1,cnt=0,D=1; while((tmp=gcd(a,x))!=1) { if(b%tmp)return -1; cnt++,b/=tmp,x/=tmp,D=(D*(a/tmp))%x; } ha[b%x]=0;ll q=1; for(int i=1;i<=m;i++)q=(q*a)%x,ha[q*b%x]=i; for(int i=1;i<=m;i++) { D=(D*q)%x; if(ha[D]){ll s=i*m-ha[D]+cnt;return (s%x+x)%x;} } return -1; } int main() { freopen("three.in","r",stdin); freopen("three.out","w",stdout); scanf("%d%d",&T,&k); for(int i=1;i<=T;i++) { scanf("%lld%lld%lld",&a,&z,&p); if(k==1)printf("%lld ",pow(a,z)); else if(k==2) { ll ans=get(a,p); if(ans==-1)puts("Orz, I cannot find x!"); else printf("%lld ",ans); } else { ll ans=exbsgs(a,z,p); if(ans==-1)puts("Orz, I cannot find x!"); else printf("%lld ",ans); } } return 0; }