hdu 5393 Falsyta in Tina Town 欧拉函数

Falsyta in Tina Town

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 548    Accepted Submission(s): 83


Problem Description
Falsyta is a lovely village girl. She loves to play with numbers besides doing housework. Her dream is to be a math teacher in a primary school.

One day when she was putting her numbers in order, she touched a variable  x  accidentally. 

The initial value of  x  was  x0 . Once  x  was touched its value would become  (kx+b) mod P

Falsyta wanted to restore it, so please help her。

Please find out the minimum touches to turn  x  back to  x0  from  x0 . If it’s impossible, please print -1.
 

Input
The first line is an integer  T , representing the number of cases。

The following  T  lines, four non-negative numbers each line,  k,b,x0,P  respectively.

1T100

0k,b,x0<p

1p109+9
 

Output
For each case, output the answer.
 

Sample Input
  
  
2 4 7 1 13 11 4 2 12
 

Sample Output
  
  
6 1
 

Source
 



思路:
本来以为是离散对数的题,但毫无疑问会tle。
(a ^ x) % p == 1 的题目可以用欧拉函数来解决,但不能暴力分解,要枚举质因子来做。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <tr1/unordered_map>
using namespace std;
using namespace std::tr1;
#define LL __int64

LL mul(LL a, LL b, LL m) {
	LL ret = 0;
	a %= m;
	while (b) {
		if (b & 1)
			ret = (ret + a) % m;
		a = (a + a) % m;
		b >>= 1;
	}
	return ret;
}
LL a_b_MOD_c(LL a, LL b, LL m) {
	LL ret = 1;
	a %= m;
	while (b) {
		if (b & 1)
			ret = mul(ret, a, m);
		a = mul(a, a, m);
		b >>= 1;
	}
	return ret;
}

bool test(LL n, LL a, LL d) {
	if (n == 2)
		return true;
	if (n == a)
		return true;
	if ((n & 1) == 0)
		return false;
	while (!(d & 1))
		d = d >> 1;
	LL t = a_b_MOD_c(a, d, n);
	while ((d != n - 1) && (t != 1) && (t != n - 1)) {
		t = mul(t, t, n);
		d = d << 1;
	}
	return (t == n - 1 || (d & 1) == 1);
}
const int Times = 10;
bool Miller_Rabin(LL n) {
	if (n < 2)
		return false;
	for (int i = 0; i <= Times; ++i) {
		LL a = rand() % (n - 1) + 1;
		if (!test(n, a, n - 1))
			return false;
	}
	return true;
}
LL pollard_rho(LL n, LL c) {
	LL i = 1, k = 2;
	LL x = rand() % (n - 1) + 1;
	LL y = x;
	while (1) {
		++i;
		x = (mul(x, x, n) + c) % n;
		LL d = __gcd((y - x + n) % n, n);
		if (1 < d && d < n)
			return d;
		if (y == x)
			return n;
		if (i == k) {
			y = x;
			k <<= 1;
		}
	}
}
LL fac[105];
int tot;
void find_fac(LL n, int c) {
	if (n == 1)
		return;
	if (Miller_Rabin(n)) {
		fac[tot++] = n;
		return;
	}
	LL p = n;
	LL k = c;
	while (p >= n)
		p = pollard_rho(p, c--);
	find_fac(p, k);
	find_fac(n / p, k);
}
void init() {
	tot = 0;
}
LL get_phi(LL x) {
	init();
	find_fac(x, 12345);
	sort(fac, fac + tot);
	LL ret = 1;
	for (int i = 0; i < tot; ++i) {
		LL sqr = fac[i] * fac[i];
		if (x % sqr)
			ret *= fac[i] - 1;
		else
			ret *= fac[i];
		x /= fac[i];
	}
	return ret;
}
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		LL k, b, x, p;
		LL ans;
		scanf("%I64d%I64d%I64d%I64d", &k, &b, &x, &p);
		if (k == 0) {
			LL tmp = (x * k + b) % p;
			if (x == tmp)
				puts("1");
			else
				puts("-1");
		} else if (k == 1) {
			if (b == 0) {
				puts("1");
			} else {
				LL ans = p / __gcd(p, b);
				printf("%I64d\n", ans);
			}
		} else {
			LL A = k;
			LL B = p * (k - 1);
			B = B / __gcd(x * (k - 1) + b, B);
			if (__gcd(A, B) != 1)
				puts("-1");
			else {
				LL phi = get_phi(B);
				LL ans = phi;
				for (LL i = 2; i * i <= phi; ++i) {
					if (phi % i == 0) {
						while (phi % i == 0)
							phi /= i;
						while (ans % i == 0 && a_b_MOD_c(A, ans / i, B) == 1)
							ans /= i;
					}
				}
				if (phi > 1 && a_b_MOD_c(A, ans / phi, B) == 1)
					ans /= phi;
				printf("%I64d\n", ans);
			}
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值