bzoj 2242 [SDOI2011]计算器 快速幂+扩展欧几里得+BSGS

1:快速幂  2:exgcd  3:exbsgs,题里说是素数,但我打的普通bsgs就wa,exbsgs就A了......

(map就是慢).....

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
#define LL long long
using namespace std;
map<long long,int> pp;
map<long long,bool> bo;
LL a,b,c;
int T,opt;
LL qp(LL a,LL b){
	LL ans=1;
	while(b){
		if(b&1)ans=(ans*a)%c;
		a=(a*a)%c;b>>=1;
	}return ans;
}
LL gcd(LL x,LL y){return y==0?x:gcd(y,x%y);}
LL exgcd(LL o,LL p,LL &x,LL &y){
	if(p==0){x=1;y=0;return o;}
	LL gcd=exgcd(p,o%p,x,y);
	LL t=x; x=y;
	y=t-(o/p)*x;
	return gcd;
}
LL exbsgs(LL a,LL b,LL c){
	pp.clear();bo.clear();
	LL g,d=1,m,now=1;int num=0;
	while((g=gcd(a,c))>1){
		if(b%g!=0)return -1;
		b/=g;c/=g;num++;
		d=(d*(a/g))%c;
	}
	//printf("num==%d\n",num);
	m=ceil(sqrt(c));
	for(int i=0;i<m;i++){
		if(!bo[now]){bo[now]=1;pp[now]=i;}
		now=(now*a)%c;
	}
	for(int i=0;i<=m;i++){
		LL x,y,e=exgcd(d,c,x,y);
		x=(x*b%c+c)%c;
		if(bo[x]) return pp[x]+i*m+num;
		d=(d*now)%c;
	}
	return -1;
}
int main(){
	scanf("%d%d",&T,&opt);
	if(opt==1){
		while(T--){
			scanf("%lld%lld%lld",&a,&b,&c);
			printf("%lld\n",qp(a,b));
		}
	}
	if(opt==2){
		while(T--){
			scanf("%lld%lld%lld",&a,&b,&c);
			LL x,y;
			LL d=exgcd(a,c,x,y);
			if(b%d!=0){printf("Orz, I cannot find x!\n");continue;}
			x*=b/d;
			LL cd=c/d;
			x=(x%cd+cd)%cd;
			printf("%lld\n",x);
		}
	}
	if(opt==3){
		while(T--){
			scanf("%lld%lld%lld",&a,&b,&c);
			LL ans=exbsgs(a,b,c);
			if(ans==-1)printf("Orz, I cannot find x!\n");
			else printf("%lld\n",ans);
		}
	}
	return 0;
}


posted @ 2017-08-15 06:30  Ren_Ivan  阅读(122)  评论(0编辑  收藏  举报