最近上課時提到的一道擴歐水題。仍是很可作的。git
咱們首先注意到,若是一個數\(s\)是符合要求的,那麼那些比它大(or 小)的數不必定符合要求。ui
所以說,答案沒有單調性,所以不能二分。spa
而後題目中也提到\(s\le 10^6\),所以咱們直接從小到大枚舉\(s\),而後考慮如何判斷。code
因爲兩個野人在有生之年不會相遇,所以只有兩種狀況:it
在處理的時候咱們把\(c_i\)都減\(1\)方便處理。io
咱們接着枚舉兩我的\(i,j\)設它們\(x\)年後相遇,而後咱們能夠列出式子:class
\(c_i+p_ix\equiv c_j+p_jx\ (mod\ s)\)gc
移項得static
\((p_i-p_j)x-sy=c_j-c_i\)di
而後就很明顯了,咱們擴歐解這個同餘方程便可,再判斷一下與\(min(l_i,l_j)\)的關係
可是注意一下枚舉的下界,從\(min(c_i)\)(注意在減\(1\)以前計算)開始
CODE
#include<cstdio> #include<cctype> using namespace std; const int N=20; int n,c[N],p[N],l[N],mx; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline int min(int a,int b) { return a<b?a:b; } inline int exgcd(int a,int b,int &x,int &y) { if (!b) { x=1; y=0; return a; } int d=exgcd(b,a%b,y,x); y-=a/b*x; return d; } inline bool check(int s) { register int i,j; for (i=1;i<n;++i) for (j=i+1;j<=n;++j) { int a=p[i]-p[j],b=s,k=c[j]-c[i],x,y; if (a<0) a=-a,k=-k; int d=exgcd(a,b,x,y); if (k%d) continue; x*=k/d; int r=b/d; if ((x%r+r)%r<=min(l[i],l[j])) return 0; } return 1; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; read(n); for (i=1;i<=n;++i) read(c[i]),mx=c[i]>mx?c[i]:mx,--c[i],read(p[i]),read(l[i]); for (i=mx;;++i) if (check(i)) return printf("%d",i),0; }