这是google 2016年校招的在线笔试第一轮,题目的链接可点击https://code.google.com/codejam/contest/4284486/dashboard,由于大多是考察基础知识,所以比竞赛题目要简单很多。
A.Googol String
注意到K最大是 1018 ,每一个字符串的前缀都是前一个字符串,因此只要找到第一个长度不小于K的 Sn ,然后递归求解就行了。由于字符串长度是指数增长的,因此递归层数很小。
GG = 10**19
sz = [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。。。