ACM-2011 Google Code jam Round 1

     伴随着Round 1C的落幕,我只能遗憾的说,今年的GCJ比赛,我到此为止了。

     今年是我第一年参加GCJ的比赛,战绩:资格赛70分,Rank:2676,Round 1A:没有参加。Round 1B:20分,Rank:1977,Round 1C:40分,Rank:1059(这次是我最接近赛点的成绩了,现在想来还是有很多遗憾的)。

     Round 1A:北京时间2011年5月21日早上9点,由于实验室集体出去春游,错过了Google Code jam Round 1A的机会,回来已经是晚上8点多了,发现Round 1A前1000名的只要过了第一道题就可以了。于是匆匆看了第一题。

     Round 1A FreeCell Statistics 第一题:题目大意为,有个人每天玩游戏,最多可以玩N把,然后已经玩了D回,赢得概率是Pd,统计到目前为止,可以玩的所有游戏回数中赢的概率为Pg。但是它忘了今天玩了多少回,总括玩了多少回G。给定三个数 N,Pd, Pg,问这个组合是否是有效的。

     分析:因为Pd始终是整数,而且是可以整除的,因此一个条件是今天赢得次数/D = Pd / 100. 而D < N,也就是能否在1-N之间找到一个数D,使得 Pd / 100 * D 刚好为一个整数,相当于D * gcd(pd, 100)/ 100为整数。gcd表示最大公约数。另D = 100 / gcd(pd,100)就可以求得最小的D了。对于任意的Pg都可以构造出来,但是有两个特殊值 0和100,当pg=0时,pd = 0;pg=100时,pd = 100;

     因此代码如下:

#include <iostream> #include <fstream> using namespace std; int cas, index=1; ifstream fin("A-large-practice.in"); ofstream fout("A-large-practice.out"); long long n, pd, pg; int gcd(int m, int n) { if (m == 0) return n; if (n == 0) return m; if (m < n) { int tmp = m; m = n; n = tmp; } while (n != 0) { int tmp = m % n; m = n; n = tmp; } return m; } void print(bool flag) { if (flag) { fout << "Case #" <<index <<": Possible"<<endl; } else { fout << "Case #" <<index <<": Broken"<<endl; } } int main() { fin >> cas; int d,ds, g, gs; while (index <= cas) { fin >> n >> pd >> pg; if (pd > 100 || pg > 100) { print(false); index ++; continue; } int temp = 0; temp = gcd(100, pd); d = 100 / temp; ds = pd / temp; if (d > n) { print(false); index ++; continue; } if (pg == 100 && pd != 100) { print(false); index ++; continue; } else if (pg == 0 && pd != 0) { print(false); index ++; continue; } else { print(true); } index ++; } return 0; }  

     由于Round 1B的时间是:北京时间2011年5月22日凌晨0点。就没有接着往下做了,等有空的时候再把剩下几道题补上吧。

     Round 1B:北京时间2011年5月22日凌晨0点。

     第一题:RPI。题目比较晦涩难懂,具体就是根据公式 RPI = 0.25 * WP + 0.50 * OWP + 0.25 * OOWP。WP,代表本队的胜率,OWP:代表跟本队比过赛的对手队伍,排除这场比赛以后的胜率和的平均(注意是比过赛的)。OOWP:是非本队队伍对OWP的一个均值。

     所以题目读懂以后,也就不难了。

#include <iostream> #include <fstream> #include <string.h> #include <iomanip> using namespace std; int cas, index=1; ifstream fin("A-large.in"); ofstream fout("A-large.out"); const int SIZE = 101; int n; char map[SIZE][SIZE]; int game[SIZE]; int win[SIZE]; double wp[SIZE]; double owp[SIZE]; double oowp[SIZE]; double result[SIZE]; void read() { memset(game, 0 , sizeof(int) * SIZE); memset(win, 0, sizeof(int) * SIZE); fin >> n; for (int i=0; i < n; i ++) { for (int j=0; j <n; j ++) { fin >> map[i][j]; if (map[i][j] == '0') { game[i] ++; } else if (map[i][j] == '1') { game[i]++; win[i] ++; }//end else if }//end for j } } void cal() { //WP for (int i=0; i < n; i ++) { wp[i] = (double)win[i] / game[i]; } for (int i =0; i < n; i ++) { int number = 0; owp[i] = 0.000000; for (int j=0; j < n; j ++) { if (map[i][j] != '.') { if (map[i][j] == '1') { owp[i] += (double)win[j] / (game[j] -1); }// else owp[i] += (double) (win[j]-1) / (game[j] -1); number ++; } } if (number != 0) { owp[i]=owp[i] / number; } } //oowp for (int i=0; i < n; i ++) { int number = 0; oowp[i] = 0.000000; for (int j=0; j < n; j ++) { if (map[i][j] != '.') { oowp[i] += owp[j]; number ++; } } if (number != 0) { oowp[i] /= number; } } for (int i=0; i < n; i ++) { result[i] = 0.25 * wp[i] + 0.50 * owp[i] + 0.25 * oowp[i]; } } void print() { fout << "Case #"<<index<<":" << endl; for (int i=0; i < n; i ++) { fout << result[i] << endl; } } int main() { fin >> cas; while (index <= cas) { read(); cal(); print(); index ++; } return 0; }  

     第二题:Revenge of the Hot Dogs 

     题目大意,有一条无限长的东西走向大街,上面有很多热狗摊子,然后为了避免他们互相争抢生意,他们之间的间距至少为D,已知热狗摊子移动速度为1米每秒,问如何移动这些摊子,使得他们的移动时间最短。

     这道题没有过。我觉得我的想法是对的,可是运行结果在Case44和Case49出错了,其他的测试用例都通过了。等有时间我过了它,在好好解释吧。错误代码如下:

#include <iostream> #include <fstream> using namespace std; int cas, index=1; ifstream fin("B-small-attempt0.in"); ofstream fout("B-small-attempt02.out"); const int SIZE = 201; int pv[SIZE][2]; int c, d; double result[SIZE]; void read() { fin >> c >> d; for (int i=1; i <= c; i ++) { fin >> pv[i][0] >> pv[i][1]; } } void revenge() { //排序 for (int i=1; i <= c; i ++) { for (int j = i+1; j <= c; j ++) { if (pv[i][0] > pv[j][0]) { pv[0][0] = pv[i][0]; pv[0][1] = pv[i][1]; pv[i][0] = pv[j][0]; pv[i][1] = pv[j][1]; pv[j][0] = pv[0][0]; pv[j][1] = pv[0][1]; } } } pv[0][0] = pv[1][0]; pv[0][1] = pv[1][1]; result[1] = (double)d / 2 * (pv[1][1]-1); for (int i=2; i <= c; i ++) { if (d < pv[i][0] - pv[0][0] - result[i-1]) { result[i] = (double)d / 2 * (pv[i][1]-1); } else if (d < pv[i][0] - pv[0][0]) { result[i] = result[i-1] + (double)(d - pv[i][0] + pv[0][0]) / 2 +(double)d / 2 * (pv[i][1]-1); } else { result[i] = result[i-1] + (double)(d - pv[i][0] + pv[0][0]) / 2 + (double)d / 2 * (pv[i][1]-1); } pv[0][0] = pv[i][0]; }//end for i } void print() { double big = 0; for (int i=1; i <=c; i ++) { if (big < result[i]) { big = result[i]; } } fout << "Case #" << index <<": " << big << endl; } int main() { fin >> cas; while (index <= cas) { read(); revenge(); print(); index ++; } return 0; }  

     第三题: House of Kittens

     没时间做了,下次再一起说吧。

     Round 1C时间:2011年5月22日下午5点开始。感觉第三轮的题目比前两轮都要简单,也是我最好的一次成绩,可惜还是没有过。

     Square Tiles:用红色2*2方块替换蓝色的方块,因为红色的方块不能重叠,所以很简单。只需要遍历一遍,看map[i][j] == '#'&&map[i+1][j] == '#' && map[i][j+1] == '#' && map[i+1][j+1] == '#',则替换,如果不是的话,则不能完全替换。

     代码如下:

#include <iostream> #include <fstream> using namespace std; int cas, index=1; ifstream fin("A-large.in"); ofstream fout("A-large.out"); const int SIZE = 52; int r,c; char map[SIZE][SIZE]; void read() { memset(map, '/0', sizeof(char) * SIZE * SIZE); fin >> r >> c; for (int i=1; i <= r; i ++) { for (int j=1; j <=c; j ++) { fin >> map[i][j]; } } } bool square() { for (int i=1; i <= r; i ++) { for (int j=1; j <= c; j ++) { if (map[i][j] == '#') { if (map[i+1][j] == '#' && map[i][j+1] == '#' && map[i+1][j+1] == '#') { map[i][j] = '/'; map[i][j+1] = '//'; map[i+1][j]= '//'; map[i+1][j+1] = '/'; } else return false; }//end if }//end fro j }//end for i return true; } void print( bool flag) { fout << "Case #"<<index<<":"<<endl; if(flag) { for (int i=1; i <=r; i ++) { for (int j=1; j <=c; j ++) { fout << map[i][j]; } fout <<endl; } } else { fout << "Impossible"<<endl; } } int main() { fin >> cas; while (index <= cas) { read(); bool flag = square(); print(flag); index ++; } return 0; }  

     Space Emergency:题目很长,很难懂。大意是飞船从0-N进行逃生,速度为0.5,然后途中可以建设L座加速器,加速器建设完成以后可以立即对飞艇进行加速,速度变成1,然后0-N的距离为a1,a2,a3,……ac的循环。

     当时这道题把我看懵了,其实可以用简单的贪心算法就可以过的。但是我没有时间去想了(感觉当时太着急了),看到小数据量的L的取值只有0 1 2三种情况,于是对三种情况做了一下简单的遍历。

     贪心算法是,在飞船加速器建设起来之前,通过的所有路径都不能进行加速,直到飞船加速器建设起来以后,选取最长的L个路径进行加速。题目太长了,看完就已经用了20分钟了(我英语实在是太烂了,这次没有通过第一轮,英语的掣肘也占到了一大部分比重)。

     小数据量代码如下:

#include <iostream> #include <fstream> using namespace std; int cas, index=1; ifstream fin("B-small-attempt1.in"); ofstream fout("B-small-attempt1.out"); const int SIZE = 1002; long long l, t, n, c; int arr[SIZE]; int load[SIZE]; void read() { fin >> l >> t >> n >> c; for (int i=0; i < c; i ++ ) { fin >> arr[i]; } for (int i=0; i< n; i ++) { load[i] = arr[i%c]; } } long long cal0() { long long sum = 0; for (int i=0; i < n; i ++) { sum += load[i]; } return sum * 2; } long long cal1(int s) { long long sum = 0; for (int i=0; i < s; i ++) { sum += load[i]; } sum *= 2; if (sum >= t) { sum += load[s]; } else if (t - sum < load[s] * 2) { sum = t + load[s] - (t - sum)/2; } else { sum += load[s] * 2; } for (int i=s+1; i < n; i ++) { sum += load[i] * 2; } return sum; } long long cal2(int x, int y) { long long sum = 0; for (int i=0; i < x; i ++) { sum += load[i]; } sum *= 2; if (sum >= t) { sum += load[x]; } else if (t - sum < load[x] * 2) { sum = t + load[x] - (t - sum)/2; } else { sum += load[x] * 2; } for (int i= x+1; i < y; i ++) { sum += load[i] * 2; } if (sum >= t) { sum += load[y]; } else if (t - sum < load[y] * 2) { sum = t + load[y] - (t - sum)/2; } else { sum += load[y] * 2; } for (int i= y +1; i <n ;i ++) { sum += load[i] * 2; } return sum; } long long cal() { long long result = 0x7fffffffffffffff; if(l == 0) { return cal0(); } if (l == 1) { result = cal0(); for (int i=0; i < n; i ++) { long long temp = cal1(i); if (result > temp) { result = temp; } } return result; } if (l == 2) { for (int i=0; i < n; i ++) { for (int j=i+1; j < n; j ++) { long long temp = cal2(i, j ); if (result > temp) { result = temp; }// }// }// return result; } } int main() { fin >> cas; while (index <= cas) { read(); long long result = cal(); fout << "Case #"<<index<<": " << result<<endl; index ++; } return 0; }  

     Perfect Harmony:题目也是很难懂啊(我英语太烂了),其实就是在L到H之间找一个数Y,使得Y能被其他音阶整除,或者可以整除其他音阶。

     小数据量很好过,遍历L到H的所有整数吧。代码如下:

#include <iostream> #include <fstream> using namespace std; int cas, index=1; ifstream fin("C-small-attempt0.in"); ofstream fout("C-small-attempt0.out"); int n, l, h; const int SIZE = 100; int arr[SIZE]; void read() { fin >> n >> l >> h; for (int i=0; i < n; i ++) { fin >> arr[i]; } } int cal() { bool flag = false; for (int i=l; i <= h; i ++) { bool flag = true; for (int j=0; j < n; j ++) { if (i > arr[j] && i % arr[j] == 0) { continue; } if (i <= arr[j] && arr[j] % i == 0) { continue; } flag = false; break; } if (flag) { return i; } } return -1; }; int main() { fin >> cas; while (index <= cas) { read(); int result = cal(); if (result == -1) { fout <<"Case #"<<index<<": NO" << endl; } else { fout << "Case #"<<index <<": "<<result << endl; } index ++; } return 0; }  

     所有题目的完整解法,等我全部做完以后,在写吧。得好好想想,自己如何提高了。

     最后附上本次排名赛中,我的成绩,就差8分钟。自己葬送了自己啊!

 

    

你可能感兴趣的:(ACM-2011 Google Code jam Round 1)