BZOJ1407: [Noi2002]Savage

Description

Input

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

Output

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

Sample Input

3
1 3 4
2 7 3
3 2 1

Sample Output

6

该样例对应于题目描述中的例子。
 
原来十几年前的计算机跑得也挺快的啊。
枚举M,再枚举两两之间的野人,然后问题转化成判断是否有一天两野人相遇。
则(P[i]-P[j])x ≡ C[j]-C[i] (Mod M)。
用拓展gcd解方程即可(注意调用gcd的时候要先让P[i]-P[j]为正)。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
typedef long long ll;
const int maxn=16;
int n,C[maxn],P[maxn],L[maxn];
void gcd(int a,int b,int& d,int& x,int& y) {
    if(!b) d=a,x=1,y=0;
    else gcd(b,a%b,d,y,x),y-=x*(a/b);
}
int check(int mod) {
    rep(i,1,n) rep(j,i+1,n) {
        int a=abs(P[i]-P[j]),b=mod,d,x,y,t=C[j]-C[i];
        gcd(a,b,d,x,y);if(P[i]<P[j]) x=-x;b/=d;
        if(t%d==0) {
            (x*=t/d)%=b;
            if(x<0) x+=b;
            if(x<=min(L[i],L[j])) return 0;
        }
    }
    return 1;
}
int main() {
    n=read();int ans=0;
    rep(i,1,n) ans=max(ans,C[i]=read()),P[i]=read(),L[i]=read();
    for(;;) {
        if(check(ans)) break;
        ans++;
    }
    printf("%d\n",ans);
    return 0;
}
View Code

 

posted @ 2016-03-31 12:55  wzj_is_a_juruo  阅读(164)  评论(0编辑  收藏  举报