BZOJ1407: [Noi2002]Savage

1407: [Noi2002]Savage

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 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

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 } 
BZOJ1407
 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 } 
BZOJ1047

 

posted @ 2018-01-16 10:38  嘒彼小星  阅读(249)  评论(2编辑  收藏  举报