[NOI2002] 荒島野人
阿新 • • 發佈:2022-05-11
二十年前的NOI是如此淳樸……
題並不難,主要是我對擴歐理解不深,再加上許久沒寫了,於是乎寫得一塌糊塗……
考慮列舉洞穴個數 \(k\) ,並驗證個數是否合法,很明顯可以列出式子(假如兩個野人 \(s\) 年後相遇):
\[c_1+p_1s\equiv c_2+p_2s\pmod{k} \]變形可得:
\[(p_1-p_2)s-rk=c_2-c_1 \]可以發現這就是一個 \(a=p_1-p_2,b=k,c=c_2-c_1\) 的不定方程,需要判斷的就是 \(x\) 是否比兩個人的壽命都要短。
首先可以肯定的是 \(c\equiv0\pmod{\gcd(a,b)}\) 不成立時方程無解,那麼野人永遠不可能相遇,顯然合法,接下來就考慮如何處理其他情況:
假設 \(g=\gcd(a,b)\) ,那麼方程可以轉化為 \(\frac{a}{g}x+\frac{b}{g}y=\frac{c}{g}\) ,其中 \(\gcd(a',b')=1\)。
\[a'x_0+b'y_0=1 \]此時應該先利用\(x_0,b'\)求出最小整數解之後再用以下公式。注意 \(b'<0\) 時要取相反數,否則求出來的東西會是負的。
\[a'(x_0c')+b'(y_0c')=c' \]最終的答案就是 \(x_0c'\) 。別的沒什麼了,就是要保證洞穴數要大於最大編號。
#include<cstdio> #define zczc #define int long long const int N=105; inline void read(int &wh){ wh=0;int f=1;char w=getchar(); while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();} while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();} wh*=f;return; } int m,c[N],p[N],l[N]; int x,y; inline int exgcd(int a,int b){ if(b==0){x=1,y=0;return a;} int re=exgcd(b,a%b); int xx=x,yy=y; x=yy,y=xx-a/b*yy; return re; } bool check(int wh){ for(int i=1;i<m;i++){ if(wh<c[i]-1)return false; for(int j=i+1;j<=m;j++){ if(wh<c[j]-1)return false; int a=p[i]-p[j],b=wh,cc=c[j]-c[i]; int g=exgcd(a,b); if(cc%g)continue; a/=g,b/=g,cc/=g; if(b<0)b=-b; x=(x*cc%b+b)%b; if(x<=l[i]&&x<=l[j])return false; } } return true; } signed main(){ #ifdef zczc freopen("in.txt","r",stdin); #endif read(m); for(int i=1;i<=m;i++){ read(c[i]);read(p[i]);read(l[i]); } for(int i=1;;i++){ if(check(i)){ printf("%lld\n",i); return 0; } } return 0; }