bzoj1407 [Noi2002]Savage——扩展欧几里得

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1407

看到一定有解,而且小于10^6,所以可以枚举;

判断一个解是否可行,就两两判断野人 i , j 能否满足在寿命内不相遇;

也就是 T*pi + ci ≡ T*pj + cj (mod m)

变成  ( pi - pj )*T + km = cj - ci

用扩展欧几里得解这个方程,得到T若大于两人中较小的寿命或无解则可行。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,c[20],p[20],l[20];
int gcd(int a,int b){return (a%b==0)?b: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;
}
bool ck(int m)
{
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
        {
            int a=p[i]-p[j],b=m,cc=c[j]-c[i];
            int g=gcd(a,b);
//            if(cc%g)return 0;
            if(cc%g)continue;//无解也满足 
            a/=g; b/=g; cc/=g;
            int x,y;
//            b=abs(b);
            if(b<0)b=-b;
            exgcd(a,b,x,y);
            x=((x*cc)%b+b)%b;//先%b! 
//            x=(x*cc+b)%b;
            if(x<=min(l[i],l[j]))return 0;
        }
    return 1;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d%d",&c[i],&p[i],&l[i]),m=max(m,c[i]);
    for(int i=m;i<=1e6;i++)
        if(ck(i))
        {
            printf("%d",i); return 0;
        }
}

 

posted @ 2018-07-01 19:26  Zinn  阅读(124)  评论(0编辑  收藏  举报