Google Code Jam Round 1A 2015 解题报告

题目链接:https://code.google.com/codejam/contest/4224486/

 

Problem A. Mushroom Monster

这题题意就是,有N个时间点,每个时间点,Kaylin可以吃掉一定数量的mushroom,Bartholomew可以放入任意数量的mushroom。

现在给出N个时间点分别有多少mushroom。

问:若Kaylin每个时间点可以吃任意数量的mushroom,那为了配合每个时间点的mushroom,Kaylin最少要吃掉多少蘑菇。

问:若Kaylin已恒定速度吃mushroom(即在每个时间点间吃的数量相同,若盘子空了则暂停进食),那为了配合每个时间点的mushroom,Kaylin最少要吃掉多少蘑菇。

 

看懂题目就是水题,第一问,只要吃掉下一个时间点相对于当前时间点减少的mushroom数量。

第二问,只要保证吃的速度要大于等于所有时间点mushroom减少的数量,即取需求速度最大值。

 

代码:

 1 #include <cstdio>

 2 #include <algorithm>

 3 #include <cstring>

 4 #include <iostream>

 5 #include <numeric>

 6 #include <queue>

 7 using namespace std;

 8 

 9 const int MAXN = 1010;

10 const int INF = 0x3f3f3f3f;

11 

12 int a[MAXN], maxr[MAXN];

13 int T, n;

14 

15 int solve1() {

16     int res = 0;

17     for(int i = 0; i < n - 1; ++i)

18         res += max(0, a[i] - a[i + 1]);

19     return res;

20 }

21 

22 int solve2() {

23     int spd = 0;

24     for(int i = 0; i < n - 1; ++i)

25         spd = max(spd, a[i] - a[i + 1]);

26     int res = 0;

27     for(int i = 0; i < n - 1; ++i)

28         res += min(a[i], spd);

29     return res;

30 }

31 

32 int main() {

33     freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);

34     scanf("%d", &T);

35     for(int t = 1; t <= T; ++t) {

36         scanf("%d", &n);

37         for(int i = 0; i < n; ++i)

38             scanf("%d", &a[i]);

39         maxr[n] = 0;

40         for(int i = n - 1; i >= 0; --i)

41             maxr[i] = max(maxr[i + 1], a[i]);

42         printf("Case #%d: %d %d\n", t, solve1(), solve2());

43     }

44 }
View Code

 

Problem B. Haircut

题目大意:已知有B个理发师,和B个理发师给任意一个人理发所需要的时间。现在有N个人在排队,若处于队首,会找当前不是正在理发的编号最小的理发师理发。

问:处于队列第N个的人会找第几个理发师。

 

思路:二分时间 time,计算在time个单位时间里,有sum人已经或正在理发,又有cnt个理发师恰好没有正在理发的人。

那么,若sum + cnt ≥ N,那么第N个人在前 time 个单位时间里,一定有机会开始理发。

如此二分可以得到第N个人开始理发的时间,再由上述的sum、cnt可以得到第N个人让第几个理发师理发。

 

代码:

 1 #include <iostream>

 2 #include <cstdio>

 3 #include <algorithm>

 4 #include <cstring>

 5 using namespace std;

 6 typedef long long LL;

 7 

 8 const int MAXN = 1010;

 9 

10 int a[MAXN];

11 int T, n, b;

12 

13 bool check(LL k) {

14     LL sum = 0, cnt = 0;

15     for(int i = 0; i < b; ++i) {

16         cnt += (k % a[i] == 0);

17         sum += (k - 1) / a[i] + 1;

18     }

19     return sum + cnt >= n;

20 }

21 

22 int solve() {

23     LL l = 0, r = LL(n) * *max_element(a, a + b);//1000000;//

24     while(l < r) {

25         LL mid = (l + r) >> 1;

26         if(!check(mid)) l = mid + 1;

27         else r = mid;

28     }

29     LL sum = 0, p = 0;

30     for(int i = 0; i < b; ++i)

31         sum += (l - 1) / a[i] + 1;

32     for(int i = 0; i < b; ++i)

33         if(l % a[i] == 0 && sum + ++p == n) return i + 1;

34     return -1;

35 }

36 

37 int main() {

38     freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);

39     scanf("%d", &T);

40     for(int t = 1; t <= T; ++t) {

41         scanf("%d%d", &b, &n);

42         for(int i = 0; i < b; ++i)

43             scanf("%d", &a[i]);

44         printf("Case #%d: %d\n", t, solve());

45     }

46 }
View Code

 

Problem C. Logging

给N个点,分别问对于每个点来说,至少删掉多少个点,能使该点在剩下的点的凸包的边上。

 

思路1:因为凸包的边的性质是:对于一条边,每个点都在其同侧。那么,O(n^2)枚举所有边,O(n)枚举所有点,看要删掉那些点。复杂度O(n^3),可以跑过小数据,牛叉的电脑可以过大数据(RMB玩家与贫民玩家的区别就体现在这里了!)

代码:

 1 #include <cstdio>

 2 #include <cstring>

 3 #include <iostream>

 4 #include <algorithm>

 5 #include <cmath>

 6 #include <vector>

 7 using namespace std;

 8 typedef long long LL;

 9 

10 const int MAXN = 3010;

11 

12 struct Point {

13     int x, y, id;

14     Point() {}

15     Point(int x, int y): x(x), y(y) {}

16     void read(int i) {

17         id = i;

18         scanf("%d%d", &x, &y);

19     }

20     Point operator - (const Point &rhs) const {

21         return Point(x - rhs.x, y - rhs.y);

22     }

23     bool operator < (const Point &rhs) const {

24         if(y != rhs.y) return y < rhs.y;

25         return x < rhs.x;

26     }

27 };

28 

29 LL cross(const Point &a, const Point &b) {

30     return (LL)a.x * b.y - (LL)a.y * b.x;

31 }

32 //ret >= 0 means turn right

33 LL cross(const Point &op, const Point &sp, const Point &ed) {

34     return cross(sp - op, ed - op);

35 }

36 

37 Point p[MAXN];

38 int ans[MAXN];

39 int n, top, T;

40 

41 void update_min(int &a, int b) {

42     if(a > b) a = b;

43 }

44 

45 void solve() {

46     for(int i = 0; i < n; ++i) for(int j = i + 1; j < n; ++j) {

47         int lsum = 0, rsum = 0;

48         for(int k = 0; k < n; ++k) {

49             LL t = cross(p[i], p[j], p[k]);

50             if(t > 0) lsum++;

51             if(t < 0) rsum++;

52         }

53         update_min(ans[i], min(lsum, rsum));

54         update_min(ans[j], min(lsum, rsum));

55     }

56 }

57 

58 int main() {

59     freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);

60     scanf("%d", &T);

61     for(int t = 1; t <= T; ++t) {

62         scanf("%d", &n);

63         for(int i = 0; i < n; ++i)

64             p[i].read(i), ans[i] = n - 1;

65         solve();

66         printf("Case #%d:\n", t);

67         for(int i = 0; i < n; ++i)

68             printf("%d\n", ans[i]);

69     }

70 }
View Code

 

思路2:枚举每一个点,其他点绕枚举点排序,用一条过枚举点的直线旋转,计算要删掉的最少点。复杂度O(n^2logn)。

代码:

 1 #include <cstdio>

 2 #include <algorithm>

 3 #include <cstring>

 4 #include <iostream>

 5 #include <cmath>

 6 using namespace std;

 7 typedef long long LL;

 8 

 9 struct Point {

10     int x, y;

11     Point() {}

12     Point(int x, int y): x(x), y(y) {}

13     Point operator - (const Point &rhs) const {

14         return Point(x - rhs.x, y - rhs.y);

15     }

16     double ang() const {

17         return atan2(y, x);

18     }

19     bool type() const {

20         if(y != 0) return y > 0;

21         return x < 0;

22     }

23 };

24 

25 LL cross(const Point &a, const Point &b) {

26     return (LL)a.x * b.y - (LL)a.y * b.x;

27 }

28 

29 const int MAXN = 3010;

30 

31 Point p[MAXN], v[MAXN << 1];

32 int n, T;

33 

34 bool cmp(const Point &a, const Point &b) {

35     if(a.type() != b.type()) return a.type() < b.type();

36     return cross(a, b) > 0;

37 }

38 

39 void solve(int n) {

40     for(int i = 1; i < n; ++i)

41         v[i - 1] = p[i] - p[0];

42     n--;

43     sort(v, v + n, cmp);

44     copy(v, v + n, v + n);

45     int res = 0;

46     for(int i = 0, j = 0; i < n; ++i) {

47         if(i == j) j++;

48         while(j < i + n && cross(v[i], v[j]) >= 0) ++j;

49         res = max(res, j - i);

50     }

51     printf("%d\n", n - res);

52 }

53 

54 int main() {

55     freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);

56     scanf("%d", &T);

57     for(int t = 1; t <= T; ++t) {

58         scanf("%d", &n);

59         for(int i = 0; i < n; ++i)

60             scanf("%d%d", &p[i].x, &p[i].y);

61         printf("Case #%d:\n", t);

62         for(int i = 0; i < n; ++i) {

63             swap(p[0], p[i]);

64             solve(n);

65             swap(p[0], p[i]);

66         }

67     }

68 }
View Code

 

你可能感兴趣的:(Google)