☆[noi2002]荒岛野人

Posted Shadow

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了☆[noi2002]荒岛野人相关的知识,希望对你有一定的参考价值。

描述 Description
克里特岛以野人群居而著称。岛上有排列成环行的M个山洞。这些山洞顺时针编号为1,2,…,M。岛上住着N个野人,一开始依次住在山洞C1,C2,…,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来。每个野人i有一个寿命值Li,即生存的年数。下面四幅图描述了一个有6个山洞,住有三个野人的岛上前四年的情况。三个野人初始的洞穴编号依次为1,2,3;每年要走过的洞穴数依次为3,7,2;寿命值依次为4,3,1。

 

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


输入格式 Input Format
第1行为一个整数N(1<=N<=15),即野人的数目。
第2行到第N+1每行为三个整数Ci, Pi, Li (1<=Ci,Pi<=100, 0<=Li<=10^6 ),表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。


输出格式 Output Format
仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。


样例输入 Sample Input
3
1 3 4
2 7 3
3 2 1

 

样例输出 Sample Output
6


时间限制 Time Limitation
1s


注释 Hint
1s


来源 Source
noi 2002 day2

 

    思路:

    这道题其实和那个青蛙约会很像的哇,这道题的野人也就15个不直接扩展欧几里得不会超时的,因为你要让每次没有两个野人在同一个山洞里(可能是野人不喜欢一起讨论哲学♂的事吧哈哈,我们假设这一全有m个山洞,我们用结构体存一下每个野人的寿命s[i].l,每个野人的初始山洞s[i].c,每个野人每次移动山洞的个数a[i].p,所以我们可以得出一个方程s[i].c+x*s[i].p≡s[j].c+x*s[j].p(mod m)。这个方程可以化简为(s[i].p-s[j].p)*x-my=s[j].c-s[i].c;我们要时这个方程无解(这样就表示野人i他永远也追不上野人j)因为每个野人还有寿命,所以当我们求出的x>min(s[i].l,s[j].l)时这时的山洞数也当然成立,因为野人i在死后才会追上野人j,所以他俩也当然不会住在一起哲♂学了哇。。。

    超时看下方↓

    {这样是不是就A了呢??当然不是你会发现超时了........这是为什么呢?(我当时也是稀里糊涂的超了)

    我还在纳闷怎么会超时,然后发现,当你在用扩展欧几里得的定理求a/d*x+b/d*y=c/d的时候要用到

    t=gcd(a,b);又因为a=s[i].p-s[j].p;这显然可以发现野人i每次跑的距离可以比野人j的少哇,所以肯定可能

    为负数...........然后你将b取个abs就好了}

 

    代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct shadow
{
    int c,p,l;
}s[1000];
int x,y;
int gcd(int a,int b)
{return b==0?a:gcd(b,a%b);}
void exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return;
    }
    exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
}
int n;
bool work(int m)
{
    int a,b,c,t,x,y;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            a=s[i].p-s[j].p;
            c=s[j].c-s[i].c;
            b=m;
            t=gcd(a,b);
            if(c%t==0)
            {
                a/=t;b/=t;c/=t;
                exgcd(a,b,x,y);
                b=abs(b);
                x=((c*x)%b+b)%b;
                if(!x)
                    x+=b;
                if(x<=min(s[i].l,s[j].l))
                    return 0;
            }
        }
    }
    return 1;
}
int main()
{
    cin>>n;
    int maxx=0;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i].c>>s[i].p>>s[i].l;
        maxx=max(maxx,s[i].c);
    }
    for(int i=maxx;;i++)
        if(work(i))
        {
            cout<<i<<endl;
            return 0;
        }
    return 0;
}
٩(๑>◡<๑)۶

 

以上是关于☆[noi2002]荒岛野人的主要内容,如果未能解决你的问题,请参考以下文章

[NOI2002] 荒岛野人 扩展欧几里得算法

BZOJ1407 NOI 2002 荒岛野人Savage

JZYZOJ1372 [noi2002]荒岛野人 扩展欧几里得

[Noi2002]Savage

bzoj1407 [Noi2002]Savage

数学 exgcdbzoj1407: [Noi2002]Savage