[NOI2002]荒岛野人(exgcd)

现在看来一道很\(exgcd\)在当年竟是一道\(NOI\)题目。

原题面

题目描述

克里特岛以野人群居而著称。岛上有排列成环行的\(m\)个山洞。这些山洞顺时针编号为\(1,2,\cdots,m\)。岛上住着\(n\) 个野人,一开始依次住在山洞\(C_1,C_2,\cdots,C_n\)中,以后每年,第\(i\)个野人会沿顺时针向前走\(P_i\)个洞住下来。

每个野人\(i\)有一个寿命值\(L_i\),即生存的年数。

下面四幅图描述了一个有\(6\)个山洞,住有三个野人的岛上前四年的情况。三个野人初始的洞穴编号依次为\(1,2,3;\)每年要走过的洞穴数依次为 \(3,7,2;\)寿命值依次为\(4,3,1\)

荒岛野人.jpeg奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个山洞中,使得小岛一直保持和平与宁静,这让科学家们很是惊奇。他们想知道,至少有多少个山洞,才能维持岛上的和平呢?

输入格式

\(n\)行为一个整数\(n(1\leq n\leq 15)\),即野人的数目。

\(2\)行到第\(N+1\)每行为三个整数\(C_i, P_i, L_i (1\leq C_i,P_i \leq 100, 0\leq L_i\leq 10^6 )\),表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。

输出格式

仅包含一个数\(M\),即最少可能的山洞数。输入数据保证有解,且 \(M\)不大于\(10^6\)

样例输入

3
1 3 4
2 7 3
3 2 1

样例输出

6

说明/提示

\(1\le N\le15\)\(1\leq C_i,P_i\leq 100\)\(0\leq L_i\leq 10^6\)

保证\(M\le10^6\)

题解

我们从小到大枚举答案,我们再枚举两个不同的野人\(i,j\),我们判断\(i,j\)在寿命值范围内能否相遇,能就说明枚举的答案不合法,如果所有\(i,j\)都不能相遇,那就说明合法,输出答案结束程序。

如何判断

我们现在的问题是如何判断他们能否相遇。

\(\forall i,j\)\(a=P_i-P_j\)即一年\(i\)\(j\)多走的步数,\(x\)天后相遇,\(b=C_j-C_i\)\(j\)初始的位置在\(i\)前面多少单位。我们的判断变为判断\(ax\equiv b(\mod M)\),我们转化一下可得\(ax+My=b\)的整数解。

这样就可以用扩展欧几里德来解决了,时间复杂度是\(O(MN^2\log M)\)可以通过本体。

code

#include<bits/stdc++.h>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
int n,c[25],p[25],l[25],w;
int max(int a,int b){return (a>b)?a:b;}
int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);
    y=y-a/b*x;
    return d;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&c[i],&p[i],&l[i]);
        w=max(w,c[i]);
    }
    for(int d,x,y,a,b;;w++)
    {
        bool flag=0;
        for(int i=1;i<n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                a=p[i]-p[j];b=c[j]-c[i];
                if(a<0)a=-a,b=-b;
                d=exgcd(a,w,x,y);
                int m=w/d;
                x=(x*b/d%m+m)%m;
                if(!x)x+=m;
                if(b%d==0&&x<=l[i]&&x<=l[j])flag=1;
                if(flag)break;
            }
            if(flag)break;
        }
        if(!flag){printf("%d",w);return 0;}
    }
    return 0;
}
posted @ 2022-04-11 21:31  董哲仁  阅读(347)  评论(0)    收藏  举报