[noi2002]荒岛野人

思路:

    这道题其实和那个青蛙约会很像的哇,这道题的野人也就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<bits/stdc++.h>
using namespace std;
int m,n,c[20],p[20],l[20];
int exgcd(int a,int b,int &x,int &y)
{
    if(!b){x=1,y=0;return a;}
    int tmp=exgcd(b,a%b,x,y);
    int t=x;x=y,y=t-(a/b)*y;
    return tmp;
}
bool bol(int m)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            int a=p[j]-p[i],b=m,cc=c[i]-c[j],x,y;
            int f=exgcd(a,b,x,y);
            if(cc%f)continue;
            a/=f,b/=f,cc/=f;
            x=(x*cc%b+b)%b;if(x<0) x-=b;
            if(x<=min(l[i],l[j]))return 0;
        }
    }
    return 1;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>c[i]>>p[i]>>l[i],m=max(m,c[i]);
    while(!bol(m)) m++;
    cout<<m;
    return 0;
}
原文地址:https://www.cnblogs.com/zzrblogs/p/10588685.html