BZOJ1407: [Noi2002]Savage
1407: [Noi2002]Savage
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 2357 Solved: 1056
[Submit][Status][Discuss]
Description
Input
第1行为一个整数N(1<=N<=15),即野人的数目。
第2行到第N+1每行为三个整数Ci, Pi, Li表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。
(1<=Ci,Pi<=100, 0<=Li<=10^6 )
Output
仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。
Sample Input
3
1 3 4
2 7 3
3 2 1
1 3 4
2 7 3
3 2 1
Sample Output
6
//该样例对应于题目描述中的例子。
//该样例对应于题目描述中的例子。
HINT
Source
【题解】
题目中说答案不超过1e6,暗示我们枚举答案。设有m个洞穴,如何判断是否可行?
对于任意i,j(i≠j0,满足对任意x,有Ci + xPi = Cj + xPj (mod m)无解或x的最小正整数解>min(l[i],l[j])
枚举i,j,判断即可
这里前者到求最小正整数解的方法
对于方程ax + by = c
设g = gcd(a,b),g | c
设a' = a/g, b' = b/g, c' = c/g
转化为a'x + b'y = c'
用exgcd求a'x + b'y = 1的解
求得x为x0,于是a'x + b'y = c'中x解集为
x = x0*c' + kb'/gcd(a', b') = x0 + kb',k∈Z
若b'为负数,需要把b'变成正数,这样变可行因为只影响y不影响x
xmin = (x * c' % b' + b') % b'
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 #define min(a, b) ((a) < (b) ? (a) : (b)) 9 #define max(a, b) ((a) > (b) ? (a) : (b)) 10 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a)) 11 inline void swap(int &a, int &b) 12 { 13 int tmp = a;a = b;b = tmp; 14 } 15 inline void read(int &x) 16 { 17 x = 0;char ch = getchar(), c = ch; 18 while(ch < '0' || ch > '9') c = ch, ch = getchar(); 19 while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); 20 if(c == '-') x = -x; 21 } 22 23 const int INF = 0x3f3f3f3f; 24 const int MAXN = 15; 25 26 int c[MAXN + 5], p[MAXN + 5], l[MAXN + 5], n, ma; 27 28 void exgcd(int a, int b, int &x, int &y) 29 { 30 if(!b){x = 1;y = 0;return;} 31 exgcd(b, a % b, y, x); 32 y -= a / b * x; 33 return; 34 } 35 int gcd(int a, int b) 36 { 37 return !b ? a : gcd(b, a % b); 38 } 39 40 bool judge(int m) 41 { 42 for(register int i = 1;i <= n;++ i) for(register int j = i + 1;j <= n;++j) 43 { 44 //先求方程 (pj - pi)x + my = ci - cj的最小正整数解x 45 int P = p[j] - p[i], C = c[i] - c[j], g = gcd(P, m), M = m, x = 0, y = 0; 46 if(C % g != 0) continue; 47 P /= g, C /= g, M /= g; 48 exgcd(P, M, x, y); 49 M = M < 0 ? -M : M; 50 x = (x * C % M + M) % M; 51 if(!x) x += M; 52 if(x <= min(l[i], l[j])) return 0; 53 } 54 return 1; 55 } 56 57 int main() 58 { 59 read(n); 60 for(register int i = 1;i <= n;++ i) read(c[i]), read(p[i]), read(l[i]), ma = max(ma, c[i]); 61 for(register int i = ma;;++ i) 62 if(judge(i)){printf("%d", i);return 0;} 63 }
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 #define min(a, b) ((a) < (b) ? (a) : (b)) 9 #define max(a, b) ((a) > (b) ? (a) : (b)) 10 #define abs(a) ((a) < 0 ? (-1 * (a)) : (a)) 11 inline void swap(int &a, int &b) 12 { 13 int tmp = a;a = b;b = tmp; 14 } 15 inline void read(int &x) 16 { 17 x = 0;char ch = getchar(), c = ch; 18 while(ch < '0' || ch > '9') c = ch, ch = getchar(); 19 while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar(); 20 if(c == '-') x = -x; 21 } 22 23 const int INF = 0x3f3f3f3f; 24 const int MAXN = 15; 25 26 int c[MAXN + 5], p[MAXN + 5], l[MAXN + 5], n, ma; 27 28 void exgcd(int a, int b, int &x, int &y) 29 { 30 if(!b){x = 1;y = 0;return;} 31 exgcd(b, a % b, y, x); 32 y -= a / b * x; 33 return; 34 } 35 int gcd(int a, int b) 36 { 37 return !b ? a : gcd(b, a % b); 38 } 39 40 bool judge(int m) 41 { 42 for(register int i = 1;i <= n;++ i) for(register int j = i + 1;j <= n;++j) 43 { 44 //先求方程 (pj - pi)x + my = ci - cj的最小正整数解x 45 int P = p[j] - p[i], C = c[i] - c[j], g = gcd(P, m), M = m, x = 0, y = 0; 46 if(C % g != 0) continue; 47 P /= g, C /= g, M /= g; 48 exgcd(P, M, x, y); 49 M = M < 0 ? -M : M; 50 x = (x * C % M + M) % M; 51 if(!x) x += M; 52 if(x <= min(l[i], l[j])) return 0; 53 } 54 return 1; 55 } 56 57 int main() 58 { 59 read(n); 60 for(register int i = 1;i <= n;++ i) read(c[i]), read(p[i]), read(l[i]), ma = max(ma, c[i]); 61 for(register int i = ma;;++ i) 62 if(judge(i)){printf("%d", i);return 0;} 63 }