Google Code Jam 2014 Round 2回顾和分析

回顾


比赛开始网络就一直在抽风,不知道宿舍网渣还是有人攻击服务器。刷了n遍n久刷出了题目。提交A小case的时候眼睁睁看着时间过去,却提交不上,这破网。最后A题B题还是解决了,C题扫了一眼,读都没读,就奔D题去了,因为我看到了熟悉的trie这个单词,加之看到小case只有9分,判断小case应该比较容易。前面因为网络浪费了很多时间,加之从未编过trie的程序,只能临时上网翻书去学,最后D小这个可以很容易暴力解的问题也没编完。

最终的rank是13xx,考虑到在这次GCJ之前从未接触过编程竞赛,而在这期间也几乎没练习,对这个结果还是比较满意的。尤其是并没有因为网络的问题心理受到多大影响,不过好像我本来就是这样的人。
比赛完看了下排名靠前的几个人,还是很震惊的。他们第一题做出来的时候我恐怕连题目都还没读完,四题全部做完的时候我可能刚刚做了第一题?更别论C和D题这种我想破脑袋也基本不会在规定时间做出来的对他们感觉也只是寻常。而智力方面绝不会有如此天壤之别,可见勤能补拙并非虚言,古之人诚不我欺!

顺带回顾下这次GCJ之前的round。

Qualification round
题目比较简单,也不限制时间,做了半天也做完了。本来也是因为临近毕业要找工作会问算法题,在小伙伴的怂恿下参与锻炼一下的,根本没打算继续参加。结果rank居然到了8xx,自信心一下爆棚,决定继续参与之后的round。

Round 1A
最后一道题都没做出来。总结了下,主要是因为没有比赛经验,以至于到这个时候完全没有比赛的状态,A题有思路最终也没做出来,B题直接就看错了题,C题据说很不寻常(题目里说的),不过对我这个新手来说真真是没这感觉。

Round1B
过了A题,C题想到算法,但始终没过。结束以后下了个答案跑了下,三个case不一样,用这几个case分析了下,结果是程序中一个小于和小于等于判断的区别。这让我认识到编程竞赛比较残酷的一面,要么全对,要么全错,but我喜欢(我真的没有受虐倾向→_→)。B题一看数据量,估计了下最多只能是O(n)的算法,可能又要有什么比特位之类的神奇操作,果断放弃了。一个教训,边界的处理要特别小心。

Round1C
A题大case和B,C的小case都过了。B的大case算法也想到了,但牵扯的部分太多,没能在规定时间内编出来,虽然经历了前面几轮,这个时候依旧经验不足啊!C的大case也有一些思路,联想到了数学里面面积相同的多边形,圆的周长最短,这题就是个离散的版本,最后的形状应该接近于圆,有时间的话打算从一个个小数据开始找找规律。

分析

题目在http://code.google.com/codejam/contest/3014486/dashboard

A题

最小的文件肯定要放到一个CD中,为充分利用这个CD的剩余空间,放入能放进的最大的文件,去掉这两个文件后再重复进行同样的过程,直到所有文件都放进CD。看起来是个不错的贪心策略,下面说明它的正确性。

假设找到了一个最优解{f1, f2},{f3, f4},…;另外,用上面说的贪心策略得到的解{fa,fb}, {fc, fd},…。{}为一个CD中的内容,
fx为这个CD文件的大小,有时CD中可能只有一个文件。现在要说明的是,贪心得到的CD数不会比最优解大。假设当前最小的文件是fa,fb是能放进装有fa的CD的最大的文件。现在从最优解中找到放fa的CD,比如{f1=fa,
f2},有f2≤fb。

若f2=fb,那么去掉fa,fb之后对剩下的文件再进行同样的论证即可。
若f2
若放进f1之后再放不进其它的文件,那么最优解中放f1的CD也没有另外的文件,去掉f1后对剩下的文件再进行同样的论证即可。

就这样将最优解向贪心获得的解转化,却不增加最优解的CD个数,可见这个贪心算法是正确的。

B题

依旧是贪心,依旧是从最小值开始考虑。o(╯□╰)o

选出数组中的最小值,这个值最后的归宿只有两种可能,要么交换到最左边,要么交换到最右边。想要交换次数最少,很自然的想法就是交换到较近的一侧。

比如数组[A1,
A2,…,Am,…An-1,An],其中Am是最小值,由于我们只在意交换的次数,而并不在意交换的顺序,比如交换A1,A2,并不会影响Am的位置,这些与Am无关的交换就可以放到后面(等Am交换到目的位置之后)去做,现在只考虑Am的交换,Am最终要么去A1的位置,要么去An的位置。并且与Am交换并不会改变剩下元素的相对位置。

假设Am离A1比较近,按上面的贪心策略交换后,得到[Am,A1,A2,..,Am-1,Am+1,…,An-1,An],而若最优解最后把Am交换到了An,那么得到[A1,A2,..,Am-1,Am+1,…,An-1,An,Am],两种情况剩下要做的都是去解[A1,A2,..,Am-1,Am+1,…,An-1,An]这个除Am之后的子数组。而贪心策略将Am交换到目标位置的次数(m-1)比最优解(n-m)更少,矛盾。因此假设(最优解将Am交换到An)不成立,最优解只能把Am交换到A1。

C题

如前所述,扫了一眼,没读,就奔D去了。

D题

对小case,可以枚举所有的分配情况,每个串都可以选择去任意一个server,最多不超过44…*4=4^8=2^16,对每个分配的情况,建trie树,计算节点个数。如前所述,这个程序没有在规定时间内编完。

我的程序

头文件就不贴了。

A题

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

int N, X;

int pack[701];

int solve() {

    int
tot=0;

    while
(N > 0) {

        for
(int ii = 1; ii <= X; ii++)

        {

            if
(pack[ii] > 0) {

                pack[ii] -= 1;

                --N;

                for
(int jj = X; jj >= 1; jj--)

                {

                    if
(jj <= X-ii && pack[jj] > 0) {

                        --N;

                        --pack[jj];

                        break;

                    }

                }

                ++tot;

            }

        }

    }

    return
tot;

}

int
main() {

    int
T;

    scanf("%d", &T);

    for
(int i = 0; i < T; ++i) {

        scanf("%d %d", &N, &X);

        fill(pack, pack+X+1, 0);

        for
(int j = 0; j < N; ++j) {

            int
dx;

            scanf("%d", &dx);

            pack[dx] += 1;

        }

        int
p = solve();

        printf("Case #%d: %d\n", i+1, p);

    }

    return
0;

}

B题


?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

int N;

int arr[1001];

int solve() {

    int
tot=0;

    int
i = 0;

    int
j = N-1;

    for
(int xx = 0; xx < N; ++xx) {

        int
min = INT_MAX;

        int
mi = -1;

        for
(int k = i; k <= j; ++k) {

            if
(arr[k] < min) {

                min = arr[k];

                mi = k;

            }

        }

        if
(mi - i < j - mi) {

            for
(int l = mi; l >i; --l) {

                arr[l] = arr[l-1];

            }

            tot += mi-i;

            ++i;

        } else
{

            for
(int l = mi; l < j; ++l) {

                arr[l] = arr[l+1];

            }

            tot += j-mi;

            --j;

        }

    }

    return
tot;

}

int
main() {

    int
T;

    scanf("%d", &T);

    for
(int i = 0; i < T; ++i) {

        scanf("%d", &N);

        for
(int j = 0; j < N; ++j) {

            scanf("%d", &arr[j]);

        }

        int
p = solve();

        printf("Case #%d: %d\n", i+1, p);

    }

    return
0;

}

C题


没做。

D题

小case结束之后编出来的,就不放了吧。
大case没做。

时间: 2024-11-05 15:05:55

Google Code Jam 2014 Round 2回顾和分析的相关文章

Google Code Jam 2014 Round 1B Problem B

二进制数位DP,涉及到数字的按位与操作. 查看官方解题报告 #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> using namespace std; #define MAX_LEN 50 long long A, B, K; int a[MAX_LEN], b[MAX_LEN], k[MAX_LEN]; long long memoize[MAX_LEN]

Google Code Jam 2009, Round 1C C. Bribe the Prisoners (记忆化dp)

Problem In a kingdom there are prison cells (numbered 1 to P) built to form a straight line segment. Cells number i and i+1 are adjacent, and prisoners in adjacent cells are called "neighbours." A wall with a window separates adjacent cells, and

Google Code Jam 2014 Round2

Google Code Jam Round2 晚上10点开始的,开始google一直上不去,然后开了个vpn就行了. 说说我的情况吧. P1就是某年noip普及组纪念品分组,贪心. p2是说给你一个排列,然后每次可以交换两个相邻的数,使得最后序列变为先上升后下降的样子.(n<=1000) 一开始题目看错了,以为是交换任意两个,然后愣了半天不会,去写后两题暴力了. (话说我Round1Cp1题目也看错了害的我逗了好久) 后来突然发现是adjacent elements...(<论英语学习的重要性

Google Code Jam 2014 总结

已经辞了,人也离开帝都了.是否还会回去? 不知道,也许脑子突然正常了又跑回去了. 如题,继续不温不火的Windows Phone. 今年2014,没错,Windows Phone是新加了好几家厂商,微软也有了更大的改变.常刷微博,看到好些人说,今年是Windows Phone年.Maybe..那么多厂商其实还是有些在观望,没啥很大的实际行动. 上次纯粹是抱怨了. 好多人评论说坚持.坚持.坚持的. Thank you.离开帝都前,参加了微软的全球开发者马拉松比赛,运气好,再加上同事的帮忙,捡了一部

Google Code Jam 2016 Round 1B B

题意:给出两个数字位数相同,分别中间有若干位不知道,用问号表示.现在要求补全这两个数字,使得差值的绝对值最小,多解则取第一个数字的值最小的,再多解就取第二个数字最小的. 分析: 类似数位dp,但是很多状态可以直接得出最终解,个别状态需要状态转移. 我们从高位到低位依次确定两个数的每个位是几.一旦确定了两个数的一个位不一样,则可以立即将小的一方的后续问号全部写9,大的一方后续问号全部写0.这样才能让差值最小. 那我们观察每个位的时候要如何确定其值呢?分如下几种情况. 1.两个数的该位都是问号,那么

Google Code Jam 2016 Round 1C C

题意:三种物品分别有a b c个(a<=b<=c),现在每种物品各选一个进行组合.要求每种最和最多出现一次.且要求任意两个物品的组合在所有三个物品组合中的出现总次数不能超过n. 要求给出一个方案,使得我们能够生成的组合数最多. 分析: 首先我们可以简单的处理一种情况,就是c<=n的情况. 因为我们枚举出了所有组合,那么两物品的出现次数的最大值不会超过c,因为A种和B种的每对组合都会在其中出现c次,其余两个的组合出现次数更少. 所以这种情况一定不会超过n,我们只需要枚举所有组合即可. 然而

2015 Google code jam Qualification Round B 枚举 + 贪心

题意:给你一个无穷长的数列 和一些非 0 的值,可以进行两种操作. 1)数列中所有大于1的值 都减1 2)从 a[i] 中取出任意的值分给任意人. 问你最少执行多少步能使的 数列全为0. 解题思路:枚举最大的a[i].大于 a[i]的部分都分出去. 解题代码: 1 // File Name: b.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月11日 星期六 23时16分58秒 4 5 #include<vector> 6 #incl

Google Code Jam 2015 Round 1A Mushroom Monster 水

题意:每10秒扫描一下盘子,查看盘子里面的面包个数,问你主角用两种吃法可能吃得的最少的面包. 1)任意吃. 2)每秒以恒定速度. 解题思路:暴力,找差值. 解题代码: 1 // File Name: a.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月18日 星期六 09时52分04秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #includ

Google Code Jam 2015 Round 1A Haircut 二分

题意:给你每个理发师的理发时间,问你排在队列中的第N个位置,问你应该被哪个理发师剪发. 解题思路:二分时间,看这个时间到第几个人理发了,然后找到临界值,看这个值的时候有那些理发师接待了新旅客的,即可找到那个理发师. 解题代码: 1 // File Name: b.sample.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月18日 星期六 09时05分30秒 4 5 #include<vector> 6 #include<lis