考场解法,比其他题解复杂,但好像顺便说明了其他题解的结论?
题意#
剪贴板 ↗ 里的题目描述比较友好。
有无限个盒子,从 开始编号,有 个球,从 开始编号。有 个人。
个人往盒子里放球,第 个人只能在编号为 的倍数的盒子放球,第 次放球的颜色编号为 .
求:编号最小的盒子,满足盒子里存在两球颜色不同。
,.
分析#
注意到 ,容易想到暴力枚举两个人,设这两人为 .
和 会在一些盒子里同时放球,这些盒子的编号为 , 是正整数。
对于第 个盒子,是 第 次放球,是 第 次放球。
对于某个 ,假设第 个盒子中, 和 所放球的颜色相同,那么有同余方程:
其中只有 是未知量,整理一下式子,即可用 求出 的最小正整数解 .
若 ,说明第 个盒子满足条件,用 更新答案。
若 ,继续判断 是否为可行解。若 ,则用 更新答案。否则 这种情况无解,对答案无贡献。
代码#
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 1008;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n, k;
inline int exgcd(int a, int b, int &x, int &y) {
if(b == 0) {
x = 1, y = 0;
return a;
}
int r = exgcd(b, a % b, x, y);
int t = x;
x = y;
y = t - a / b * y;
return r;
}
inline int gcd(int a, int b) {
if(b == 0) return a;
return gcd(b, a % b);
}
int t[MAXN], x[MAXN], y[MAXN];
signed main() {
scanf("%lld%lld", &n, &k);
for(int i = 1; i <= k; i++) {
scanf("%lld%lld%lld", &t[i], &x[i], &y[i]);
}
int ans = inf;
for(int i = 1; i <= k; i++) {
for(int j = 1; j <= k; j++) {
if(i == j) continue;
int xx, yy;
int Lcm = t[i] / gcd(t[i], t[j]) * t[j];
int a = Lcm / t[i] * y[i] - Lcm / t[j] * y[j];
int b = x[j] - x[i] + y[i] - y[j];
if(a < 0 && b < 0) continue;
int d = gcd(a, n);
if(b % d != 0) {
ans = min(ans, Lcm);
continue;
} else {
exgcd(a, n, xx, yy);
int tmp = ((b/d*xx) % (n/d) + (n/d)) % (n/d);
if(tmp >= 2) ans = min(ans, Lcm);
if(tmp == 1 && (n/d) != 1) {
ans = min(ans, 2 * Lcm);
}
}
}
}
if(ans == inf) cout << "Mystia will cook forever...\n";
else cout << ans - 1 << endl;
return 0;
}
cpp