NOI2002 荒岛野人

可以发现转圈的过程类似于对一个数进行取模,所以我们不妨将所有的点下标设为以0开始,即对于输入的ci,我们将其减1

还可以发现答案不超过106,意味着我们可以枚举答案,然后检查答案是否合法。

容易发现ans不合法,当且仅当存在1i,jn,满足:

ci+kpicj+kpjmodans

注意到这里只有一个未知数k,很像同余方程中ax1modp的形式。

所以接下来就是喜闻乐见的推式子环节:

ci+kpicj+kpjmodans

cicj+k(pipj)0modans

k(pipj)cjcimodans

这时就和同余方程中的解法一样,设另一个未知数l,满足:

k(pipj)+lans=cjci

当然这里l可以是负数,但必须为整数。

那么我们惊喜的发现,这个方程长得像ax+by=c的形式,而这显然可以使用exgcd求出一对合法的x,y,然后找到k0的最小的整数解。(l可以为负数,但k必须是自然数)

如果在枚举i,j时遇到不合法的可以直接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;
}
posted @   Nastia  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示