Google APAC 2016 University Graduates Test Round A解题报告

来源:互联网 发布:数据库通配符 编辑:程序博客网 时间:2024/04/30 11:44

测试结果

这是google 2016年校招的在线笔试第一轮,题目的链接可点击https://code.google.com/codejam/contest/4284486/dashboard,由于大多是考察基础知识,所以比竞赛题目要简单很多。

A.Googol String

注意到K最大是1018,每一个字符串的前缀都是前一个字符串,因此只要找到第一个长度不小于K的Sn,然后递归求解就行了。由于字符串长度是指数增长的,因此递归层数很小。

GG = 10**19sz = [0]while sz[-1] < GG:    sz.append(sz[-1] * 2 + 1)R = lambda: int(raw_input().strip())T = R()def solve(pos, kk):    assert(sz[pos] >= kk)    mid = sz[pos] / 2 + 1    if kk == mid: return 0    elif kk < mid: return solve(pos - 1, kk)    else:        kk -= mid        return 1 - solve(pos - 1, sz[pos - 1] - kk + 1)for i in xrange(T):    print 'Case #' + str(i + 1) + ': ',    K = R()    print solve(len(sz) - 1, K)

B.gCube

将各个维度相乘就可以算出体积,对于目标长度,可以通过二分得到答案。我一开始没注意到大数据会有乘法溢出的问题,导致大数据挂了,要不然就满分了。。。解决浮点乘法溢出的办法也很简单:取对数。把乘法变成加法。

#include <bits/stdc++.h>#define FOR(i, n) for (int i = 0; i < n; ++i)using namespace std;typedef long long ll;typedef pair<int, int> point;void solve() {    int N, Q, l, r;    cin >> N >> Q;    vector<double> arr(N);    FOR(i, N) cin >> arr[i];    FOR(i, Q) {        cin >> l >> r;        long double cur = 0.0;        for (int j = l; j <= r; ++j) {            cur += log(arr[j]);        }        long double low = 0.0, up = 1e10;        int cnt = 0;        while (cnt < 1000) {            ++cnt;            long double mid = (low + up) / 2.0;            long double val = (long double)(r - l + 1) * log(mid);            if (val > cur) up = mid;            else low = mid;        }        cout << fixed << setprecision(10) << (low + up) / 2.0 << endl;    }    return;}int main() {    int TestCase;    cin >> TestCase;    FOR(caseID, TestCase) {        cout << "Case #" << caseID + 1 << ":" << endl;        solve();    }    return 0;}

C. gCampus

简单来说,就是要求判断一条边是否有可能出现在最短路上,一个比较简单的图论题。首先通过floyd算法求出所有点对之间的最短路径,时间复杂度O(N3),然后对于每一条边(u,v),枚举所有的顶点对,判断是否有下式成立:

distance(i, j) = distance(i, u) + w(u, v) + distance(v, j)

如果上式对于某个(i,j)顶点对成立,则说明(u,v)这条边在某条最短路径上。

#include <bits/stdc++.h>#define FOR(i, n) for (int i = 0; i < n; ++i)using namespace std;typedef long long ll;typedef pair<int, int> point;const ll INF = (ll)1e14;struct Edge {    int from, to, idx;    ll wei;    Edge(int _f, int _t, ll _w, int _i): from(_f), to(_t), wei(_w), idx(_i) {}};void solve() {    int n, m, x, y;    ll w;    scanf("%d %d", &n, &m);    vector<Edge> arr;    ll g[105][105];    FOR(i, n) FOR(j, n) {        if (i == j) g[i][j] = 0;        else g[i][j] = INF;    }    FOR(i, m) {        cin >> x >> y >> w;        g[x][y] = min(g[x][y], w);        g[y][x] = min(g[y][x], w);        arr.push_back(Edge(x, y, w, i));    }    ll dis[105][105];    FOR(i, n) FOR(j, n) {        dis[i][j] = g[i][j];    }    FOR(k, n) FOR(i, n) FOR(j, n) {        dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);    }    vector<bool> ok(m, false);    FOR(i, m) {        int f = arr[i].from, t = arr[i].to;        ll w = arr[i].wei;        FOR(j, n) FOR(k, n) {            if (ok[i] || dis[j][k] == dis[j][f] + w + dis[t][k]) {                ok[i] = true;                break;            }        }        if (!ok[i]) {            cout << i << endl;        }    }    return;}int main() {    int TestCase;    cin >> TestCase;    FOR(caseID, TestCase) {        cout << "Case #" << caseID + 1 << ":" << endl;        solve();    }    return 0;}

D.gSnake

一个看上去比较麻烦的模拟题,google每年都会出这种题目,关键在于要把思路理清楚,让代码尽量简洁一点,否则很容易出bug。

对于贪吃蛇的身体,由于每次只是头部和尾部可能发生变化,因此只需要维护一个双端队列deque,每次向前移动,删除尾部元素,更新头部元素即可。

对于吃食物,可以用一个集合set来维护那些食物已经被吃过了,虽然总的食物点可能达到1010,但注意到Xi不超过106,而一旦没有了命令,贪吃蛇只能在一个方向前进,最多额外吃105单位食物,因此内存是完全可以承受的。

对于判断贪吃蛇是否因为碰到自己身体而死的情况,可以用哈希表map来维护每个位置上的贪吃蛇身体数目,一旦发现一个位置上出现了超过一个贪吃蛇身体,就说明它碰到了自己的身体,游戏结束。

最终代码只有80行。

#include <bits/stdc++.h>#define FOR(i, n) for (int i = 0; i < n; ++i)using namespace std;typedef long long ll;typedef pair<int, int> point;typedef pair<int, char> rec;const int dir_x[] = {1, 0, -1, 0};const int dir_y[] = {0, -1, 0, 1};set<point> eat;inline bool has_food(point& pos) {    int cc = pos.first + pos.second;    if (cc % 2 == 0) return false;    if (eat.find(pos) != eat.end()) return false;    return true;}inline void eat_food(point& pos) {    eat.insert(pos);}void solve() {    int Q, row, col;    cin >> Q >> row >> col;    deque<point> snake;    eat.clear();    int d = 3, ptr = 0;    vector<rec> cmd(Q);    FOR(i, Q) cin >> cmd[i].first >> cmd[i].second;    sort(cmd.begin(), cmd.end());    map<point, int> visited;    snake.push_back({0, 0});    visited[{0, 0}] = 1;    int tt = 1;    while (true) {        if (tt > 1500000) {            cout << snake.size() << endl;            return;        }        point tp = snake.front();        tp.first = (tp.first + dir_x[d] + row) % row;        tp.second = (tp.second + dir_y[d] + col) % col;        if (!has_food(tp)) {            --visited[snake.back()];            if (visited[snake.back()] == 0) visited.erase(snake.back());            ++visited[tp];            if (visited[tp] >= 2) {                cout << snake.size() << endl;                return;            }            snake.push_front(tp);            snake.pop_back();        }        else {            eat_food(tp);            ++visited[tp];            if (visited[tp] >= 2) {                cout << snake.size() << endl;                return;            }            snake.push_front(tp);        }        if (ptr < cmd.size() && cmd[ptr].first == tt) {            if (cmd[ptr].second == 'L') d = (d - 1 + 4) % 4;            else {                d = (d + 1) % 4;                assert(cmd[ptr].second == 'R');            }            ++ptr;        }        ++tt; // increase clock    }    return;}int main() {    int TestCase;    cin >> TestCase;    FOR(caseID, TestCase) {        cout << "Case #" << caseID + 1 << ": ";        solve();    }    return 0;}

第一次用markdown在csdn上写博客,请大家多指教。

也祝2016年毕业的童鞋拿到理想的offer,我参加这个笔试完全是for fun,对于被我挤掉名额的那个同学说一声sorry。。。

0 0
原创粉丝点击