Google APAC Round D题解
2015-11-08 23:30
393 查看
Problem A. Dynamic Grid
最基础的搜索,我用DFS做的,标记棋盘上每一个位置初始化为未搜索,遍历整个棋盘,如果遇到1且以前从没搜索到的话就从该点开始不停搜索,直到搜完,复杂度O(m*n)
Problem B. gBalloon
很有意思的题目,首先考虑不可能的情况:
1.如果风向和距离的乘积为正数或者0(距离不为0),那么一定需要移动这个气球(称之为坏球),记下所需要的最小的消耗,如果所有坏球所需最小消耗的和大于q,那么不可能。
2.考虑如果需要移动气球,那么肯定是在时刻0的时候移动,我们用set维护一个3-element entry记录(当前气球标号,该球消耗的能量,到达0位置所需要的时间),并按最后一项的值从大向小排序。初始化时所有好球消耗的能量为0,时间根据dis/v向上取整。所有坏球计算所需最小的消耗和时间。每次从set中拿出第一位的项(时间最长),因为是它限制了最后到达的时间,给他能量看能否快过第二项,如果在当前能量+之前消耗的 可以保证他快过第二项,那么更新该项并且重新插入,同时更新剩余的能量。如果不能的话则循环结束,将所有的剩余能量尝试更新最开始的项,返回该项所需的时间。
因为每次消耗的q会最少增加1,所以总得复杂度是O(q * m * logn)
Problem C. IP Address Summarization
这题当时卡了挺长时间,题意就是求最小的能表示当前网段的一个集合,因为比如1.0.0.0/9和1.128.0.0/9是可以合写成1.0.0.0/8的。对于斜杠后面的数我称它为掩码最低位。声明32个hashset,对于每个IP,先将其标准化后(和掩码&一下),然后转化为long long(高低位要分清楚,我是按照题意直接记录的,即1.0.0.0为00000001.24个0),因为32位数最高不超过2^32-1。根据掩码最低位的不同insert到不同的hashset里,这样先去重,然后从第32个hashset开始遍历所有的值,如果对第i个hashset的第j个值,设为val,如果val在第i位(从高向低)为1,那么看一下是否val去掉该位的值(val-(1<<(32-i))也在该hashset中,如果在的话就向前一个hashset中插入(val-(1<<(32-i)),当前hashset的不急着删除,反正下一步也会删除掉。
接下来就是去掉重合的subnet,仍旧从第32个hashset开始,对于每一项,如果一个一个去掉2进制中得1之后,所得到的值在之前的某个hashset中出现,则说明前面的subnet可以覆盖当前的,删掉即可。
复杂度为O(32 * 32 * n)
这题本身不难,我写的可能复杂了很多,主要是当时index从0或者从1开始理解起来很混乱,想清楚了以后实现还是很简单,位操作还是能解决很多问题的
Problem D. Virtual Rabbit
没做出来,感觉没什么头绪,待我研究了大神的代码以后补上
最基础的搜索,我用DFS做的,标记棋盘上每一个位置初始化为未搜索,遍历整个棋盘,如果遇到1且以前从没搜索到的话就从该点开始不停搜索,直到搜完,复杂度O(m*n)
代码
int m, n; int q; char b[110][110]; bool flag[110][110]; bool valid(int x ,int y) { if(x < 0 || x >= m) return false; if(y < 0 || y >= n) return false; if(flag[x][y] == 1) return false; if(b[x][y] != '1') return false; return true; } void DFS(int x ,int y) { flag[x][y] = 1; if(valid(x - 1, y)) DFS(x - 1, y); if(valid(x + 1, y)) DFS(x + 1, y); if(valid(x, y - 1)) DFS(x, y -1); if(valid(x, y + 1)) DFS(x, y + 1); } int solve() { ZERO(flag); int count = 0; FOR(i,0,m) FOR(j,0,n) { if(b[i][j] == '1' && flag[i][j] == false) { DFS(i,j); count++; } } return count; } int main(){ int Tcase; cin >> Tcase; FOR(hh,0,Tcase) { cin >> m >> n; FOR(i,0,m) FOR(j,0,n) cin >> b[i][j]; cin >> q; cout << "Case #" << hh + 1 << ":" << endl; char ops; FOR(i,0,q) { cin >> ops; if(ops == 'Q') cout << solve() << endl; else { int x ,y; char val; cin >> x >> y >> val; b[x][y] = val; } } } return 0; }
Problem B. gBalloon
很有意思的题目,首先考虑不可能的情况:
1.如果风向和距离的乘积为正数或者0(距离不为0),那么一定需要移动这个气球(称之为坏球),记下所需要的最小的消耗,如果所有坏球所需最小消耗的和大于q,那么不可能。
2.考虑如果需要移动气球,那么肯定是在时刻0的时候移动,我们用set维护一个3-element entry记录(当前气球标号,该球消耗的能量,到达0位置所需要的时间),并按最后一项的值从大向小排序。初始化时所有好球消耗的能量为0,时间根据dis/v向上取整。所有坏球计算所需最小的消耗和时间。每次从set中拿出第一位的项(时间最长),因为是它限制了最后到达的时间,给他能量看能否快过第二项,如果在当前能量+之前消耗的 可以保证他快过第二项,那么更新该项并且重新插入,同时更新剩余的能量。如果不能的话则循环结束,将所有的剩余能量尝试更新最开始的项,返回该项所需的时间。
因为每次消耗的q会最少增加1,所以总得复杂度是O(q * m * logn)
#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a)) #define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a)) #define LL long long #define ALL(v) v.begin(),v.end() #define ZERO(v) memset(v, 0, sizeof v) #define NEG(v) memset(v, -1, sizeof v) #define F first #define S second #define PB push_back #define MP make_pair #define MOD 1000000007 #define PI 3.141592653589793 inline long double min(long double a , long double b) {if(a < b)return a; return b;} inline long double max(long double a , long double b) {if(a < b)return b; return a;} int m, n; int q; int speed[1100]; pair<int,int> pos[110]; set<pair<int,int>,greater<pair<int,int> > > uset; int calc(int p, int s) { if(p * s >= 0) return INT_MAX; int t = p / s; if(t * s == p) return abs(t); else return abs(t) + 1; } int solve() { int sum = 0; int flag[110]; int energy[110]; ZERO(energy); ZERO(flag); FOR(i,0,n) { if(pos[i].first == 0) continue; int p = pos[i].first; int h = pos[i].second; if(speed[h] * p == 0 || speed[h] * p > 0) { flag[i] = 1; } else { int t = p / speed[h]; if(t * speed[h] == p) uset.insert(MP(abs(t),i)); else uset.insert(MP(abs(t) + 1, i)); } } int eng = 0; FOR(i,0,n) { if(!flag[i]) continue; int p = pos[i].first; int h = pos[i].second; int MIN = q + 1; int index = -1; for(int j = 0; j < m; j++) { if(speed[j] * p < 0) { if(abs(j - h) < MIN) { MIN = abs(j - h); index = j; } } } if(index == -1) return -1; int t = p / speed[index]; if(speed[index] * t == p) uset.insert(MP(abs(t), i)); else uset.insert(MP(abs(t) + 1, i)); flag[i] = MIN; energy[i] = MIN; eng += MIN; } if(eng > q) return -1; int remain = q - eng; while(remain > 0) { pair<int,int> slow = *(uset.begin()); uset.erase(uset.begin()); int limit = slow.first; if(uset.size()) limit = uset.begin()->first; int ii = slow.second; int p = pos[ii].first; int h = pos[ii].second; remain += energy[ii]; int index= -1; int MIN = m + 1; int T = -1; for(int i = max(0, h - remain); i <= min(m - 1, h + remain); i++) { int tt = calc(p, speed[i]); if(tt < limit) { if(abs(i - h) < MIN) { MIN = abs(i - h); index = i; T = tt; } } } if(index == -1 || remain < MIN) { uset.insert(slow); break; } energy[ii] = MIN; remain -= MIN; uset.insert(MP(T,ii)); } int ii = uset.begin()->second; int tt = uset.begin()->first; int p = pos[ii].first; int h = pos[ii].second; for(int i = max(0, h - remain); i <= min(m - 1, h + remain); i++) { int t = calc(p, speed[i]); tt = min(tt,t); } return tt; } int main(){ int Tcase; cin >> Tcase; FOR(hh,0,Tcase) { cin >> n >> m >> q; FOR(i,0,m) cin >> speed[i]; FOR(i,0,n) cin >> pos[i].first >> pos[i].second; cout << "Case #" << hh + 1 << ": "; uset.clear(); int res = solve(); if(res != -1) cout << res << endl; else cout << "IMPOSSIBLE" << endl; } return 0; }
Problem C. IP Address Summarization
这题当时卡了挺长时间,题意就是求最小的能表示当前网段的一个集合,因为比如1.0.0.0/9和1.128.0.0/9是可以合写成1.0.0.0/8的。对于斜杠后面的数我称它为掩码最低位。声明32个hashset,对于每个IP,先将其标准化后(和掩码&一下),然后转化为long long(高低位要分清楚,我是按照题意直接记录的,即1.0.0.0为00000001.24个0),因为32位数最高不超过2^32-1。根据掩码最低位的不同insert到不同的hashset里,这样先去重,然后从第32个hashset开始遍历所有的值,如果对第i个hashset的第j个值,设为val,如果val在第i位(从高向低)为1,那么看一下是否val去掉该位的值(val-(1<<(32-i))也在该hashset中,如果在的话就向前一个hashset中插入(val-(1<<(32-i)),当前hashset的不急着删除,反正下一步也会删除掉。
接下来就是去掉重合的subnet,仍旧从第32个hashset开始,对于每一项,如果一个一个去掉2进制中得1之后,所得到的值在之前的某个hashset中出现,则说明前面的subnet可以覆盖当前的,删掉即可。
复杂度为O(32 * 32 * n)
这题本身不难,我写的可能复杂了很多,主要是当时index从0或者从1开始理解起来很混乱,想清楚了以后实现还是很简单,位操作还是能解决很多问题的
#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a)) #define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a)) #define LL long long #define ALL(v) v.begin(),v.end() #define ZERO(v) memset(v, 0, sizeof v) #define NEG(v) memset(v, -1, sizeof v) #define F first #define S second #define PB push_back #define MP make_pair #define MOD 1000000007 #define PI 3.141592653589793 inline long double min(long double a , long double b) {if(a < b)return a; return b;} inline long double max(long double a , long double b) {if(a < b)return b; return a;} int n; unordered_set<LL> uset[33]; string conv(LL val) { vector<int> res(4); for(int i = 3; i >= 0 ; i--) { res[i] = val % 256; val /= 256; } string r; FOR(i,0,res.size()) { r += to_string(res[i]); r.PB('.'); } r.pop_back(); return r; } vector<int> split(string s) { int pos2 = s.find('.'); int pos1 = 0; vector<string> res; while(pos2 != -1) { res.PB(s.substr(pos1, pos2 - pos1)); pos1 = pos2 + 1; pos2 = s.find('.', pos1 ); } if(pos1 != s.size()) res.PB(s.substr(pos1)); vector<int> ans; FOR(i,0,res.size()) ans.PB(stoi(res[i])); return ans; } void clearPos(LL &val, LL base) { if((val & base) == 0) return; val -= base; } int main(){ int Tcase; cin >> Tcase; FOR(hh,0,Tcase) { FOR(i,0,33) uset[i].clear(); cin >> n; FOR(i,0,n) { string s; cin >> s; int pos = s.find('/'); int val = stoi(s.substr(pos + 1)); vector<int> temp = split(s.substr(0,pos)); LL tmp = 0; LL base = 1; for(int j = 3; j >= 0; j--) { tmp += base * temp[j]; base *= 256; } //cout << conv(tmp) << endl; base = 1LL <<(32 -val); base /= 2; for(int j = val + 1; j <= 32; j++,base /= 2) { clearPos(tmp,base); } uset[val].insert(tmp); } LL base = 1; for(int i = 32; i >= 1; i--, base *= 2) { ITE(j,uset[i]) { LL val = *j; if((val & base) != 0) { LL val2 = val - base; if(uset[i].count(val2) == 1) uset[i- 1].insert(val2); } else { LL val2 = val | base; if(uset[i].count(val2) == 1) uset[i- 1].insert(val); } } } base = 1; for(int i = 32; i >= 1; i--, base *= 2) { vector<LL> E; ITE(j,uset[i]) { LL tmpBase = base; LL val = *j; clearPos(val, tmpBase); tmpBase *= 2; bool flag= false; for(int k = i - 1; k >= 0; k--, tmpBase *= 2) { if(uset[k].count(val) == 1) { flag = true; break; } clearPos(val, tmpBase); } if(flag) E.PB(*j); } FOR(j,0,E.size()) uset[i].erase(E[j]); } set<pair<LL,int> > ans; for(int i = 32; i >= 1; i--, base *= 2) { ITE(j,uset[i]) { ans.insert(MP(*j,i)); } } cout << "Case #" << hh + 1 << ":" << endl; ITE(i,ans) cout << conv(i->first) << "/" << i->second << endl; // cout << solve() << endl; } return 0; }
Problem D. Virtual Rabbit
没做出来,感觉没什么头绪,待我研究了大神的代码以后补上
相关文章推荐
- 谷歌正式开始补偿Nexus 6P重启门和电池门用户:最高赔400美元
- 谷歌、雅虎支持中文域名搜索 有助提升搜索引擎优化
- 谷歌音乐搜索栏的提示功能php修正代码
- 超级推荐:艾一搜 http://www.iesool.com
- google访问速度很慢
- 月光微博客
- 月光微博客
- [IT资讯]谷歌收购摩托罗拉移动
- 月光微博客
- Google程序调用的注意事项
- 调查:Bing和雅虎搜索对谷歌形成有力挑战
- 一次谷歌面试趣事
- 周鸿祎:揭露谷歌Chrome浏览器的“阳谋”
- fedora 19安装谷歌浏览器
- 传谷歌欲10亿美元收购聊天应用WhatsApp
- 硬件开源之殇
- 程序员薪水最高的25家公司 Juniper第一,谷歌第二
- 为何Google比苹果和微软更需要HTML5?
- Google Search By Image(用图搜图)的chrome扩展