TonyYin's Blog

Back

考场解法,比其他题解复杂,但好像顺便说明了其他题解的结论?

题意#

剪贴板 里的题目描述比较友好。

有无限个盒子,从 11 开始编号,有 nn 个球,从 00 开始编号。有 kk 个人。

kk 个人往盒子里放球,第 ii 个人只能在编号为 tit_i 的倍数的盒子放球,第 jj 次放球的颜色编号为 [xi+(j1)×yi]modn[x_i+(j-1)\times y_i]\bmod n.

求:编号最小的盒子,满足盒子里存在两球颜色不同。

n109n\leq 10^9k103k\leq 10^3.

分析#

注意到 k103k\leq 10^3,容易想到暴力枚举两个人,设这两人为 (u,v)(u, v).

uuvv 会在一些盒子里同时放球,这些盒子的编号为 c×lcm(tu,tv)c\times \operatorname{lcm}(t_u, t_v)cc 是正整数。

对于第 c×lcm(tu,tv)c\times \operatorname{lcm}(t_u, t_v) 个盒子,是 uulcm(tu,tv)tu×c\dfrac{\operatorname{lcm}(t_u, t_v)}{t_u}\times c 次放球,是 vvlcm(tu,tv)tv×c\dfrac{\operatorname{lcm}(t_u, t_v)}{t_v}\times c 次放球。

对于某个 cc,假设第 c×lcm(tu,tv)c\times \operatorname{lcm}(t_u, t_v) 个盒子中,uuvv 所放球的颜色相同,那么有同余方程:

xu+(c×lcm(tu,tv)tu1)yuxv+(c×lcm(tu,tv)tv1)yv(modn)x_u+(c\times \frac{\operatorname{lcm}(t_u, t_v)}{t_u}-1)\cdot y_u \equiv x_v+(c\times \frac{\operatorname{lcm}(t_u, t_v)}{t_v}-1)\cdot y_v \pmod{n}

其中只有 cc 是未知量,整理一下式子,即可用 ExGcd\rm{ExGcd} 求出 cc 的最小正整数解 cminc_{min}.

cmin2c_{min}\geq 2,说明第 lcm(tu,tv)\operatorname{lcm}(t_u, t_v) 个盒子满足条件,用 lcm(tu,tv)\operatorname{lcm}(t_u, t_v) 更新答案。

cmin=1c_{min}=1,继续判断 c=2c=2 是否为可行解。若 c2c\neq 2,则用 2×lcm(tu,tv)2\times \operatorname{lcm}(t_u, t_v) 更新答案。否则 (u,v)(u, v) 这种情况无解,对答案无贡献。

代码#

#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
【洛谷-P7835】「Wdoi-3」夜雀 dreaming
https://www.tonyyin.top/blog/oi-solution/p7835
Author TonyYin
Published at August 24, 2021
Comment seems to stuck. Try to refresh?✨