1. 程式人生 > >bzoj1407: [Noi2002]Savage(擴歐)

bzoj1407: [Noi2002]Savage(擴歐)

題目描述:

 

輸入格式:第一行一個整數,表示野人的數目。

                 第2~n+行每行三個整數ci, pi, li,表示每個野人初始住的洞穴編號,每年走過的洞穴數和壽命值。

 

輸出格式:一個數m表示最少的洞穴數。

 

輸入樣例:

3
1 3 4
2 7 3
3 2 1

 

輸出樣例:

6

//該樣例對應題目中描述的例子

 

解析:對於每個m,對於每兩個野人可以列出式子 c[i] + p[i] * x = c[j] + p[j] * x (mod m)

          轉化為方程即為 (p[i] - p[j]) * x + m * k = c[j] - c[i]

          於是用擴歐求解 x 即可,若無解或解出的 x 比兩個野人壽命的最小值大,說明兩個野人在有生之年不會相會。

          這樣判斷完每一對野人,若每一對都成立,則說明這個m可行。

          由於資料很小,所以m暴力列舉即可。

 

程式碼如下:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 const int maxn = 20;
 6 int n, c[maxn], p[maxn], l[maxn], mx, x, y;
 7 
 8 int read(void) {
 9     char c; while (c = getchar(), c < '0' || c >'9'); int x = c - '0';
10     while (c = getchar(), c >= '
0' && c <= '9') x = x * 10 + c - '0'; return x; 11 } 12 13 int exgcd(int a, int b) { //擴歐 14 if (!b) { 15 x = 1; y = 0; return a; 16 } 17 int d = exgcd(b, a % b); 18 int t = x; x = y; y = t - (a / b) * y; 19 return d; 20 } 21 22 int pd(int m) { 23 for (int i = 1; i <= n; ++ i) 24 for (int j = i + 1; j <= n; ++ j) { 25 int a = p[i] - p[j], b = m, d = c[j] - c[i]; 26 if (a < 0) a = -a, d = -d; //由於a為非負數,所以若a<0,則將a變為-a 27 int g = exgcd(a, b); 28 if (d % g) continue; 29 a /= g; b /= g; d /= g; x *= d; 30 x = (x % b + b) % b; //求最小的正整數解 31 if (!x) x += b; 32 if (x <= min(l[i], l[j])) return 0; //不成立,直接退出 33 } 34 return 1; 35 } 36 37 int main() { 38 n = read(); 39 for (int i = 1; i <= n; ++ i) c[i] = read(), p[i] = read(), l[i] = read(), mx = max(mx, c[i]); 40 for (int i = mx; i ; ++ i) { //列舉m 41 if (pd(i)) return printf("%d", i); 42 } 43 return 0; 44 }