[BZOJ 1467] [POJ 3243] clever Y

本文深入探讨了扩展BSGS算法的应用,特别是在解决形式为AX≡B(mod C)的问题上,当A、C不互质时的处理方法。通过实例演示了如何通过调整原式子来适配扩展BSGS算法,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BZOJ传送门
POJ传送门

题目描述

小Y发现,数学中有一个很有趣的式子: X Y   m o d   Z = K X^Y\ mod\ Z = K XY mod Z=K 给出 X X X Y Y Y Z Z Z,我们都知道如何很快的计算 K K K。但是如果给出 X X X Z Z Z K K K,你是否知道如何快速的计算 Y Y Y呢?

输入输出格式

输入格式

本题由多组数据(不超过20组),每组测试数据包含一行三个整数 X X X Z Z Z K K K 0 ≤ X , Z , K ≤ 1 0 9 0 \le X, Z, K \le 10^9 0X,Z,K109)。 输入文件一行由三个空格隔开的 0 0 0结尾。

输出格式

对于每组数据:如果无解则输出一行No Solution,否则输出一行一个整数 Y ( 0 ≤ Y &lt; Z ) Y(0 \le Y &lt; Z) Y(0Y<Z),使得其满足 X Y   m o d   Z = K X^Y\ mod\ Z = K XY mod Z=K,如果有多个解输出最小的一个 Y Y Y

输入输出样例

输入样例#1:
5 58 33
2 4 3
0 0 0
输出样例#1:
9
No Solution

解题分析

一道扩展 B S G S BSGS BSGS的板题。

一般的 B S G S BSGS BSGS只能解决 A X ≡ B ( m o d   C ) A^X\equiv B(mod\ C) AXB(mod C) C C C为质数的情况, 如果 A 、 C A、C AC不互质就凉凉了。

d = g c d ( A , C ) d=gcd(A,C) d=gcd(A,C), 那么我们可以将这个式子拆开成 A d A x − 1 ≡ B d ( m o d   C d ) \frac{A}{d}A^{x-1}\equiv \frac{B}{d}(mod\ \frac{C}{d}) dAAx1dB(mod dC), 如此反复操作最后可以得到 P × A x − n u m ≡ B ′ ( m o d   C ′ ) P\times A^{x-num}\equiv B&#x27;(mod\ C&#x27;) P×AxnumB(mod C)。 这时候就可以用普通的 B S G S BSGS BSGS搞操作了。

不过显然我们现在的 x &gt; n u m x&gt;num x>num, 所以我们暴力枚举 x ≤ n u m x\le num xnum的情况就好。

代码如下:

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cctype>
#include <map>
#define W while
#define IN inline
#define gc getchar()
#define R register
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
std::map <int, int> mp;
int exgcd(R int a, R int b, int &x, int &y)
{
	if(!b) return x = 1, y = 0, a;
	int ret = exgcd(b, a % b, x, y);
	int buf = x; x = y, y = buf - a / b * y;
	return ret;
}
IN int EXBSGS(R int A, R int B, R int MOD)
{
	if(MOD == 1) if(!B) return 0; else return -1;
	if(B == 1) if(A) return 0; else return -1;
	if(!(A % MOD)) if(!B) return 1; else return -1;
	int num = 0, now = 1, seg = 1, gcd, x, y, bd = std::ceil(std::sqrt(MOD));
	mp.clear();
	W ((gcd = exgcd(A, MOD, x, y)) > 1)
	{
		if(B % gcd) return -1;
		B /= gcd, MOD /= gcd; ++num;
		now = 1ll * now * A / gcd % MOD;
	}
	for (R int i = 0, val = 1; i <= num; ++i, val = 1ll * val * A % MOD)
	if(val == B) return i;
	for (R int i = 0; i < bd; ++i, seg = 1ll * seg * A % MOD) if(!mp.count(seg)) mp[seg] = i;
	for (R int i = 0; i < bd; ++i, now = 1ll * now * seg % MOD)
	{
		gcd = exgcd(now, MOD, x, y);
		x = (1ll * x * B % MOD + MOD) % MOD;
		if(mp.count(x)) return i * bd + mp[x] + num;
	}
	return -1;
}
int main(void)
{
	R int A, B, MOD, ans;
	W (~scanf("%d%d%d", &A, &MOD, &B))
	{
		if(!(A | B | MOD)) break;
		ans = EXBSGS(A, B, MOD);
		if(ans < 0) puts("No Solution");
		else printf("%d\n", ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值