1. 程式人生 > >bzoj1407 / P2421 [NOI2002]荒島野人(exgcd)

bzoj1407 / P2421 [NOI2002]荒島野人(exgcd)

P2421 [NOI2002]荒島野人

洞穴數不超過1e6 ---> 列舉

判斷每個野人兩兩之間是否發生衝突:exgcd

假設有$m$個洞穴,某兩人(設為1,2)在$t$時刻發生衝突

那麼我們可以列出方程

$c_{1}+p_{1}t\equiv c_{2}+p_{2}t (mod\quad m)$

移項一下:$(p_{1}-p_{2})t\equiv c_{2}-c_{1} (mod\quad m)$

去掉$(mod m)$,得$(p_{1}-p_{2})t-mx=c_{2}-c_{1} $

這不就是不定方程標準形式$ax+by=c$嗎!

用exgcd搞搞,求出$t$的最小正整數解

如果$t<=min(l_{1},l_{2})$說明在兩隻的有生之年會發生衝突

此時$m$是不合法的,向下列舉就行了

複雜度$O(1e6n^{2}logp_{max})$,然鵝實際效率遠高於介個

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define re register
 5 using namespace std;
 6 int min(int a,int b){return a<b?a:b;}
 7 int
max(int a,int b){return a>b?a:b;} 8 #define N 17 9 int n,C[N],p[N],l[N],x0,y0,g; 10 void exgcd(int a,int b,int &x,int &y){ 11 if(!b) g=a,x=1,y=0; 12 else exgcd(b,a%b,y,x),y-=x*(a/b); 13 } 14 bool check(int b){ 15 for(int i=1,a,c,q;i<=n;++i) 16 for(int j=i+1;j<=n;++j){
17 a=((p[i]-p[j])%b+b)%b,c=C[j]-C[i]; 18 exgcd(a,b,x0,y0);q=b/g;//求ax+by=gcd(a,b) 19 if(c%g) continue; 20 x0=(x0*c/g%q+q)%q;//先*c/g轉成原來的式子,再%(b/gcd(a,b))得到最小解 21 if(0<=x0&&x0<=min(l[i],l[j])) 22 return 0; 23 } 24 return 1; 25 } 26 int main(){ 27 scanf("%d",&n); int st=0; 28 for(int i=1;i<=n;++i) 29 scanf("%d%d%d",&C[i],&p[i],&l[i]),st=max(st,C[i]); 30 for(re int i=st;i<=1000000;++i)//注意是從洞穴編號最大的那個開始列舉 31 if(check(i)){printf("%d",i);break;} 32 return 0; 33 }
View Code