NOI2002 荒岛野人
可以发现转圈的过程类似于对一个数进行取模,所以我们不妨将所有的点下标设为以开始,即对于输入的,我们将其减。
还可以发现答案不超过,意味着我们可以枚举答案,然后检查答案是否合法。
容易发现不合法,当且仅当存在,满足:
注意到这里只有一个未知数,很像同余方程中的形式。
所以接下来就是喜闻乐见的推式子环节:
这时就和同余方程中的解法一样,设另一个未知数,满足:
当然这里可以是负数,但必须为整数。
那么我们惊喜的发现,这个方程长得像的形式,而这显然可以使用exgcd求出一对合法的,然后找到的最小的整数解。(可以为负数,但必须是自然数)
如果在枚举时遇到不合法的可以直接break,这样能使程序快不止一点。
代码:
#include <bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl
using ll = long long;
ll exgcd(ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
ll ans = exgcd(b, a % b, x, y), tmp = x;
x = y, y = tmp - a / b * y;
return ans;
}
int n;
ll c[20], p[20], l[20];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%lld%lld%lld", &c[i], &p[i], &l[i]);
c[i]--;
}
for (ll ans = *std::max_element(c + 1, c + n + 1) + 1;; ans++) {
int can = 1;
for (int i = 1; i <= n && can; i++) {
for (int j = 1; j <= n && can; j++) {
if (i == j || p[i] > p[j])
continue;
ll x = 0, y = 0, rec = exgcd(-(p[i] - p[j]), ans, x, y);
x = x * (c[i] - c[j]) / rec, y = y * (c[i] - c[j]) / rec;
if ((c[j] - c[i]) % rec != 0)
continue;
ll M = ans / rec;
x = (x % M + M) % M;
if (x <= l[i] && x <= l[j])
can = 0;
}
}
if (can) {
printf("%lld\n", ans);
exit(0);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话