
分析两个野人的情况,设山洞数目为m,如果i和j在第x年相遇,那么可以得到一个同余方程ci+x*pi=cj+x*pj(mod m),即(pi-pj)*x=cj-ci(mod m)。所以要使两个野人不能相遇,只需该同余方程无解或者x比其中一个野人的寿命长。推广到n个野人两两不相遇,只需任意两个野人满足上述条件,因为n很小,所以可以枚举。
我们一开始将m赋值为max{c[i]},每次判断m是否可行,如果可行即为答案,否则就将m加1。在判断m是否可行时要用到扩展欧几里得算法求。
注意:扩展欧几里得算法求满足ax=gcd(a,b) (mod b)的x的最小正整数解时,要将x对b/gcd(a,b)取模,而不是对b取模。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 20 using namespace std; int n,mx,c[maxn],p[maxn],l[maxn]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void exgcd(int a,int b,int &d,int &x,int &y) { if (!b) { d=a;x=1;y=0; } else { exgcd(b,a%b,d,y,x); y-=x*(a/b); } } inline bool judge(int m) { F(i,1,n-1) F(j,i+1,n) { int d,x,y,dd=((c[j]-c[i])%m+m)%m,a=((p[i]-p[j])%m+m)%m; exgcd(a,m,d,x,y); if ((dd%d)!=0) continue; int mm=m/d; int k=(dd/d*x%mm+mm)%mm; if (k<=l[i]&&k<=l[j]) return false; } return true; } int main() { n=read(); mx=0; F(i,1,n) { c[i]=read();p[i]=read();l[i]=read(); mx=max(mx,c[i]); c[i]--; } while (1) { if (judge(mx)) break; mx++; } printf("%d\n",mx); }
原文:http://blog.csdn.net/aarongzk/article/details/50649807