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
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; }