2242: [SDOI2011]计算器(数论)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq872425710/article/details/82869080

题目大意:

给你三个操作
1:求a^b=x(%p)
2:求a*b=x(%p)
3:求a^x=b(%p)

思路:

这是数论里面比较好的题了,第一问快速幂,第二问扩展gcd,第三问BSGS。
第三问a^x=b(%p),因为过p个肯定有一个循环节,飞马小定理可得,那么我们把x分成根号p块,设为a ^(i*m)a ^j=b(%p),移项可得 a j = b i n e ( a i m ) a^j=b*ine(a^{i*m}) ine为逆元,左边的放到hash里面,然后计算右边的在hash里面找,找到了说明im+j就是答案了。

程序:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
#include<cmath>
#define LL long long
using namespace std;

map<int,int> mp;
int t,k,y,z,p;
void exgcd(int a,int b,int &x,int &y){
	if (!b){
		x=1; y=0; return;
	}
	exgcd(b,a%b,x,y);
	int tmp=x;
	x=y;
	y=tmp-a/b*y;
}

int gcd(int x,int y){
	if (!y) return x;
	return gcd(y,x%y);
}

int ksm(int x,int y,int mo){
	if (y==1) return x;
	if (!y) return 1;
	int o=ksm(x,y/2,mo);
	o=((LL)o*o)%mo;
	if (y%2==1) o=((LL)o*x)%mo;
	return o;
}

void solve1(int x,int y,int p){
	printf("%d\n",ksm(x,y,p));
}

void solve2(int a,int z,int b){
	int x,y;
	int t=gcd(a,b);
	if (z%t>0){
		printf("Orz, I cannot find x!\n");
		return;
	}
	exgcd(a,b,x,y);
	if (x<0) x=(x+b)%b;
	printf("%d\n",(LL)x*z%b);
}

void solve3(int y,int z,int p){
	y%=p;
	if (!y&&!z){
		printf("%d\n",1);
		return;
	}
	if (!y){
		printf("Orz, I cannot find x!\n");
		return;
	}
	mp.clear();
	int m=ceil(sqrt(p)),t=1;
	mp[1]=m+1;
	for (int i=1;i<m;i++){
		t=(LL)t*y%p;
		if (!mp[t]) mp[t]=i;
	}
	int tmp=ksm(y,p-m-1,p),ine=1;
	for (int i=0;i<m;i++){
		int k=mp[(LL)z*ine%p];
		if (k){
			if (k==m+1) k=0;
			printf("%d\n",i*m+k);
			return;
		}
		ine=(LL)ine*tmp%p;
	}
	printf("Orz, I cannot find x!\n");
}

int main(){
	scanf("%d%d",&t,&k);
	for (int i=1;i<=t;i++){
		scanf("%d%d%d",&y,&z,&p);
		if (k==1) solve1(y,z,p);
		if (k==2) solve2(y,z,p);
		if (k==3) solve3(y,z,p);
	}
}

猜你喜欢

转载自blog.csdn.net/qq872425710/article/details/82869080