[BZOJ2242][SDOI2011]计算器

[BZOJ2242][SDOI2011]计算器

试题描述

你被要求设计一个计算器完成以下三项任务:
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)的最小非负整数。

输入

输入包含多组数据。

第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。
以下行每行包含三个正整数y,z,p,描述一个询问。

输出

对于每个询问,输出一行答案。对于询问类型2和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”,注意逗号与“I”之间有一个空格。

输入示例

3 1
2 1 3
2 2 3
2 3 3

输出示例

2
1
2

数据规模及约定

对于100%的数据,1<=y,z,p<=10^9,为质数,1<=T<=10。

题解

第一问快速幂,第二问求逆元,第三问用 BSGS。

BSGS 就是中途相遇的一个应用,我们可以令 x = km + b,于是有 ykm Ξ z·y-b (mod p),那么当 m = sqrt(n) 时,k 和 b 都不超过 sqrt(n),所以我们先枚举 b,然后把所有的 z·y-b 扔进 hash,然后再枚举 k 看看能不能匹配上。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
using namespace std;

int read() {
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
	return x * f;
}

#define LL long long
#define oo 2147483647

LL Pow(int a, int b, int p) {
	LL ans = 1, t = a;
	while(b) {
		if(b & 1) (ans *= t) %= p;
		(t *= t) %= p; b >>= 1;
	}
	return ans;
}

void gcd(int a, int b, LL& x, LL& y) {
	if(!b){ x = 1; y = 0; return ; }
	gcd(b, a % b, y, x); y -= a / b * x;
	return ;
}
LL Inv(int y, int p) {
	if(y % p == 0) return -233;
	LL x, k;
	gcd(y, p, x, k);
	return (x % p + p) % p;
}

#define maxn 100010
#define MOD 100007
int ToT, head[maxn], nxt[maxn], num[maxn];
LL val[maxn];
int Find(LL x) {
	int u = x % MOD;
	for(int e = head[u]; e; e = nxt[e]) if(val[e] == x) return num[e];
	return -233;
}
void Insert(LL x, int v) {
	int u = x % MOD;
	nxt[++ToT] = head[u]; val[ToT] = x; num[ToT] = v; head[u] = ToT;
	return ;
}

int main() {
	int T = read(), K = read();
	while(T--) {
		int y = read(), z = read(), p = read();
		if(K == 1) printf("%d\n", (int)Pow(y, z, p));
		if(K == 2) {
			LL tmp = Inv(y, p);
			if(tmp < 0) puts("Orz, I cannot find x!");
			else printf("%d\n", (int)(tmp * z % p));
		}
		if(K == 3) {
			if(y % p == 0){ puts("Orz, I cannot find x!"); continue; }
			int m = sqrt(p);
			memset(head, 0, sizeof(head)); ToT = 0;
			LL val = z % p, invy = Inv(y, p);
			for(int i = 0; i < m; i++, (val *= invy) %= p)
				if(Find(val) < 0) Insert(val, i);
			val = 1;
			bool ok = 0;
			for(int i = 0; i * m <= p; i++, (val *= Pow(y, m, p)) %= p) if(Find(val) >= 0) {
				printf("%d\n", i * m + Find(val)); ok = 1; break;
			}
			if(!ok) puts("Orz, I cannot find x!");
		}
	}
	
	return 0;
}

 

posted @ 2017-04-12 09:47  xjr01  阅读(258)  评论(0编辑  收藏  举报