洛谷 [P2485] 计算器

快速幂+同余方程+BSGS

同余方程在解的时候要注意,在将exgcd求出的解变换为原方程的解的时候,要取模
BSGS的原理就是用分块+hash优化暴力,要注意特判 a 和 b 是 p 的倍数的时候.
对于预处理,要预处理出来, $0 \sim t $的Hash值,以处理 答案是 0 的情况

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#define ll long long
using namespace std;
ll p, a, b, n, opt;
ll quick_mod(ll n, ll k, ll p) {
	ll ans = 1;
	while(k) {
		if(k & 1ll) (ans *= n) %= p;
		(n *= n) %= p;
		k >>= 1;
	}
	return ans;
}
ll exgcd(ll a, ll b, ll &x, ll &y) {
	if(!b) {
		x = 1; y = 0;
		return a;
	}
	ll t = exgcd(b, a % b, x, y);
	ll k = y;
	y = x - a / b * y;
	x = k;
	return t;
}
void work2() {
	ll r1, r2;
	ll t = exgcd(a, p, r1, r2);
	if(b % t) {printf("Orz, I cannot find x!\n");return;}
	r1 *= b / t;
	r1 %= (p / t);
	(r1 += (p / t)) %= (p / t);
	printf("%lld\n", r1);
}
void BSGS() {
	b %= p;
	if(a % p == 0) {
		if(b == 1) {printf("0\n");return;}
		if(!b) {printf("1\n");return;}
		printf("Orz, I cannot find x!\n");
		return;
	}
	map <int, int> Hash;
	Hash.clear();
	ll t = ceil(sqrt(p)),  k = 1ll;
	for(int i = 0; i <= t; i++) {
		Hash[b * k % p] = i;
		(k *= a) %= p;
	}
	ll tmp = quick_mod(a,  t, p), ans = tmp;
	for(int i = 1; i <= t; i++) {
		if(Hash.find(ans) != Hash.end()){
			printf("%lld\n", i * t - Hash[ans]);
			return;
		}
		(ans *= tmp) %= p;  
	}
	printf("Orz, I cannot find x!\n");
}
int main() {
	cin >> n >> opt;
	for(int i = 1; i <= n; i++) {
		cin >> a >> b >> p;
		switch(opt) {
			case 1 : printf("%lld\n", quick_mod(a, b, p));break;
			case 2 : work2();break;
			case 3 : BSGS();break;
		}
	}
	return 0;
}
posted @ 2018-03-12 10:49  Mr_Wolfram  阅读(156)  评论(0编辑  收藏  举报