题解 P5345 【【XR-1】快乐肥宅】
在博客园食用更佳:https://www.cnblogs.com/PinkRabbit/p/LuoguP5345.html。
很荣幸为 X Round 1 贡献了自己的一题。
题意简述:
给定
求关于
题解:
分为两个部分解决。
第一部分:分别求出每个方程的解。
首先观察
定义
从
可以看到,出现了长度为
-
如果
r=245760 ,则x\equiv 7\pmod{5} ,且x\ge 7 。 -
如果
r=12544 ,则x=4 。 -
如果
r=2 ,则无解。
以上就是每个方程的
那么,问题就是,如何区分这
首先,需要将
而且可以发现,若在“尾巴”上找到了解,那么就只有一组解。所以需要判断一个值是否在尾巴上。
其实这是很简单的,如果
据此,我们区分了在“尾巴”上的解,也就是只有一组解的情况,接下来考虑不在“尾巴”上的情况。
因为解不在“尾巴”上,则如果解不在循环内就是无解了,所以首先判断解是否在循环内。
假设第一个在循环上的数为
令
可以进一步化为
这是因为循环内的值均是
令
使用 BSGS 求出
再使用 BSGS 求出
则原方程的解为
至此,第一部分解决。
第二部分:合并每个方程的解。
首先,若前面的方程出现了无解的情况,则方程组也无解。
若前面的方程出现了只有唯一解的情况,只需要检查此唯一解是否满足所有方程即可。
接下来讨论以上每个方程的解均形如
分开考虑前半部分和后半部分,对于前半部分,显然是 ExCRT 的形式。
对于后半部分,可以化为
考虑使用 ExCRT 解决前半部分,令前
但是这里出现一个问题,那就是
因为以上方程的解
考虑这样一种情况:long long 能够表示的范围。
这时其实不需要再合并了,只需要判断
最后,当方程成功合并完之后,
此时可以再考虑
若
据此写出代码,复杂度
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define Fail return puts("Impossible"), 0
#define mp std::make_pair
typedef long long LL;
typedef std::pair<int, int> pii;
const int MG = 10000005, MS = 3175;
const int U = 1e9;
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
template<typename T>
T exgcd(T a, T b, T &x, T &y) {
if (!b) return x = 1, y = 0, a;
int d = exgcd(b, a % b, y, x);
return y -= a / b * x, d;
}
int buk[MG], stk[MS];
inline int BSGS(int a, int b, int m) {
int S = sqrt(m - 1) + 1;
int A = 1, f = -1, t = 0;
for (int i = 0; i < S; ++i) {
buk[stk[++t] = (LL)b * A % m] = i;
A = (LL)A * a % m;
}
int C = 1;
for (int i = 1; !~f && i <= S; ++i)
if (~buk[C = (LL)C * A % m])
f = i * S - buk[C];
while (t) buk[stk[t--]] = -1;
return f;
}
inline pii ExBSGS(int a, int b, int m) {
int o = 0, A = 1 % m, d = 1, nd, x, y;
while (1) {
if (d == (nd = gcd((LL)A * a % m, m))) break;
if (A == b) return mp(o, -1);
++o, A = (LL)A * a % m, d = nd;
}
if (b % d) return mp(-1, -1);
m /= d, b /= d, A /= d;
exgcd(A, m, x, y);
b = (LL)b * (x + m) % m;
x = BSGS(a, b, m);
if (!~x) return mp(-1, -1);
y = BSGS(a, 1 % m, m);
return mp(x % y + o, y);
}
inline bool Combine(LL &a1, LL &m1, LL a2, LL m2) {
LL k1, k2, g = exgcd(m1, m2, k1, k2);
if ((a2 - a1) % g) return 0;
a1 += (k1 * ((a2 - a1) / g) % m2 + m2) * m1 % (m1 / g * m2);
return a1 %= m1 *= m2 / g, 1;
}
const int MN = 1005;
int N;
int k[MN], r[MN], g[MN];
int x[MN], q[MN], X, MaxX;
int main() {
memset(buk, -1, sizeof buk), X = -1;
scanf("%d", &N);
for (int i = 1; i <= N; ++i) {
scanf("%d%d%d", &k[i], &g[i], &r[i]);
pii ans = ExBSGS(k[i] % g[i], r[i] % g[i], g[i]);
x[i] = ans.first, q[i] = ans.second;
if (!~x[i]) Fail;
if (!~q[i]) X = x[i];
MaxX = std::max(MaxX, x[i]);
}
if (~X) {
for (int i = 1; i <= N; ++i) {
if (~q[i] && (X < x[i] || (X - x[i]) % q[i])) Fail;
if (!~q[i] && X != x[i]) Fail;
}
return printf("%d\n", X), 0;
}
LL P = 0, Q = 1;
for (int i = 1; i <= N; ++i) {
if (Q > U && (P - x[i]) % q[i]) Fail;
if (Q <= U && !Combine(P, Q, x[i] % q[i], q[i])) Fail;
}
if (P < MaxX) P += ((MaxX - P - 1) / Q + 1) * Q;
if (P > U) Fail;
printf("%lld\n", P);
return 0;
}