谷歌中国算法比赛解题报告 APAC2016B
2016-11-06 06:50
666 查看
Problem A. Travel
[b]Problem B. gWheels
[/b]
[b][b]Problem C. gNumbers
[/b][/b]
[b][b]Problem
D. Albocede DNA
[/b][/b]
[b][b]1.
这道题,根据题目的数据,如果能早到一个点,一定不比晚到差,所以本质上还是一个DFS,就是有点麻烦,但比起APAC2015C的那道metro题要简单多了。把该定义的定义好,条理搞清晰些很容易过。[/b][/b]
[b][b]2.
这道题,典型的先计算一遍所有 p,t的比例组合,存进map里,然后O(n2)扫描e数组,对任意两个数字,看看能不能组成的齿轮组能不能在p,t组合中找到,找到就输出YES,退出,如果全部扫描完都找不到yes,就输出no。[/b][/b]
实现后发现大数据有些慢,看了大神的做法,也都是一样,所以这应该是最优的……
3. 博弈问题,一般来说,博弈问题的经典解法就是,如果我能找到一个获胜点,我就获胜,如果我一个都找不到,我就失败,但因为每次都两个人来回选,所以如果对方失败,我就获胜,对方获胜,我就失败。 也是就说,假设DFS会返回true,false,那么如果第k层返回false,对于第k-1层就是true……大概就是这个意思,DFS的每一层都要把下一层的结果反一下
针对这个题,同样DFS,对每个人,先查当前数字会不会输,会输就直接返回,否则,遍历这个数字的质数因子,去查生成的新数字,对方会不会输,如果对方会输,则返回赢,如果查完了所有的对方都不会输,则返回自己会输
大数据还要注意先生成一个质数库,为了方便我用set存了,注意虽然题目数据上限10的15次方,但只要找3.2*(10**7)(比平方根大就行,32000000写着方便……)以内的质数即可。暴力生成这些质数也就几秒钟的事
4.这个题很难很麻烦
大神的DP我还没来得及看,本人的思想是将ab组成pair, cd 组成pair, 然后对每个ab pair, 去找后面所有能组合的 cd pair。 具体思路如下:
先开一个数组,对每个对应位置是a的,记录以这个a开头有多少种DNA
对每个对应位置是d的,找后面所有的a,因为d可以连任意一个a,所以存下d总共可以连多少种情况,把每个a存的数量加起来
对每个对应位置是c的,找后面任意一个c,然后以这两个c为起点终点,计算有多少种c的情况(需要用到预选生成的组合库),以这个c为终点找d,记录每个cd pair有多少种
对每个对应位置是b的,把从这个b开始的后面所有c的每种情况都加过来,方便a找b时直接用(不用再加了,这是一步重要减枝)
对每个对应位置是a的,找到后面任意一个a,这两个a作为起点终点,然后在找后面的b,对每个ab pair, 找这个b 存的 cd pair 有没有对应的, 最后a记录所有从这个a开始有多少DFA
从后往前扫描:执行上面的步骤
最后,小数据可以轻松过,但是大数据要处理超时……再做一个减枝,如果ab,cdpair 任意一个数字超过250 就直接舍弃,数据量减了一半,时间上勉勉强强够
至于如何更快的解,请下大神的代码看……我没仔细研究,但基本思想看起来差不多
最后 附上代码
8649
[b]Problem B. gWheels
[/b]
[b][b]Problem C. gNumbers
[/b][/b]
[b][b]Problem
D. Albocede DNA
[/b][/b]
[b][b]1.
这道题,根据题目的数据,如果能早到一个点,一定不比晚到差,所以本质上还是一个DFS,就是有点麻烦,但比起APAC2015C的那道metro题要简单多了。把该定义的定义好,条理搞清晰些很容易过。[/b][/b]
[b][b]2.
这道题,典型的先计算一遍所有 p,t的比例组合,存进map里,然后O(n2)扫描e数组,对任意两个数字,看看能不能组成的齿轮组能不能在p,t组合中找到,找到就输出YES,退出,如果全部扫描完都找不到yes,就输出no。[/b][/b]
实现后发现大数据有些慢,看了大神的做法,也都是一样,所以这应该是最优的……
3. 博弈问题,一般来说,博弈问题的经典解法就是,如果我能找到一个获胜点,我就获胜,如果我一个都找不到,我就失败,但因为每次都两个人来回选,所以如果对方失败,我就获胜,对方获胜,我就失败。 也是就说,假设DFS会返回true,false,那么如果第k层返回false,对于第k-1层就是true……大概就是这个意思,DFS的每一层都要把下一层的结果反一下
针对这个题,同样DFS,对每个人,先查当前数字会不会输,会输就直接返回,否则,遍历这个数字的质数因子,去查生成的新数字,对方会不会输,如果对方会输,则返回赢,如果查完了所有的对方都不会输,则返回自己会输
大数据还要注意先生成一个质数库,为了方便我用set存了,注意虽然题目数据上限10的15次方,但只要找3.2*(10**7)(比平方根大就行,32000000写着方便……)以内的质数即可。暴力生成这些质数也就几秒钟的事
4.这个题很难很麻烦
大神的DP我还没来得及看,本人的思想是将ab组成pair, cd 组成pair, 然后对每个ab pair, 去找后面所有能组合的 cd pair。 具体思路如下:
先开一个数组,对每个对应位置是a的,记录以这个a开头有多少种DNA
对每个对应位置是d的,找后面所有的a,因为d可以连任意一个a,所以存下d总共可以连多少种情况,把每个a存的数量加起来
对每个对应位置是c的,找后面任意一个c,然后以这两个c为起点终点,计算有多少种c的情况(需要用到预选生成的组合库),以这个c为终点找d,记录每个cd pair有多少种
对每个对应位置是b的,把从这个b开始的后面所有c的每种情况都加过来,方便a找b时直接用(不用再加了,这是一步重要减枝)
对每个对应位置是a的,找到后面任意一个a,这两个a作为起点终点,然后在找后面的b,对每个ab pair, 找这个b 存的 cd pair 有没有对应的, 最后a记录所有从这个a开始有多少DFA
从后往前扫描:执行上面的步骤
最后,小数据可以轻松过,但是大数据要处理超时……再做一个减枝,如果ab,cdpair 任意一个数字超过250 就直接舍弃,数据量减了一半,时间上勉勉强强够
至于如何更快的解,请下大神的代码看……我没仔细研究,但基本思想看起来差不多
最后 附上代码
#include <stdio.h> #include <iostream> #include <fstream> #include <math.h> #include <algorithm> #include <vector> #include <set> #include <map> #include <hash_map> #include <hash_set> #include <unordered_map> #include <unordered_set> #include <string.h> #include <queue> #include <list> #include <iomanip> using namespace std; #define ll long long #define uint unsigned int #ifndef INT_MAX #define INT_MAX 0x7fffffff #endif class PA { public: PA(){} int M, N, K; struct Road { int id; int from; int to; vector<int> timesTaken; Road(){ id = from = to = 0; } int getUsedTime(int currTime) { return timesTaken[currTime%24]; } int getEndCity(int from_) { if (from_ == from) return to; else return from; } }; struct City { int id; vector<int> roadId; City(){ id = 0; } }; vector<Road> roads; vector<City> cities; vector<pair<int, int>> queries; vector<vector<int>> visited; void DFS(int start, int time, int end,int begin) { if (start == end) { visited[begin][start] = min(visited[begin][start], time); return; } if (visited[begin][start] <= time) return; visited[begin][start] = time; for (int i = 0; i < cities[start].roadId.size(); i++) { int roadid = cities[start].roadId[i]; int to = roads[roadid].getEndCity(start); DFS(to, roads[roadid].getUsedTime(time) + time, end,begin); } } void SingleProcess(ofstream& fout) { visited.clear(); visited.resize(24,vector<int>(N, INT_MAX)); for (int i = 0; i < 24; i++) { DFS(0, i, INT_MAX,i); } for (int i = 0; i < queries.size(); i++) { if (visited[queries[i].second%24][queries[i].first] == INT_MAX) { fout << -1 << " "; } else fout << visited[queries[i].second % 24][queries[i].first] - (queries[i].second % 24) << " "; } } void run() { FILE* fp = freopen("in.txt", "r", stdin); ofstream fout("out.txt"); int Cases = 0; scanf("%d", &Cases); for (int time = 0; time < Cases; time++) { cin >> N >> M >> K; cities.clear(); cities.resize(N); roads.clear(); roads.resize(M); queries.clear(); queries.resize(K); for (int i = 0; i < N; i++) { cities[i].id = i; } for (int i = 0; i < M; i++) { roads[i].id = i; cin >> roads[i].from >> roads[i].to; roads[i].from--; roads[i].to--; cities[roads[i].from].roadId.push_back(i); cities[roads[i].to].roadId.push_back(i); roads[i].timesTaken.resize(24, 0); for (int j = 0; j < 24; j++) { cin >> roads[i].timesTaken[j]; } } for (int i = 0; i < K; i++) { cin >> queries[i].first >> queries[i].second; queries[i].first--; queries[i].second; } fout << "Case #" << (time + 1) << ": "; SingleProcess(fout); fout << endl; std::cout << time << endl; } fclose(fp); fout.close(); } }; class PB { public: PB(){} int NP, NE,NT; int M; ll GCD(ll v1, ll v2) { while (v1) { ll temp = v1; v1 = v2%v1; v2 = temp; } return v2; } set<pair<ll,ll>> eeset, ptset; vector<ll> pvec, evec, tvec; vector<pair<ll, ll>> queries; void SingleProcess(ofstream& fout) { ptset.clear(); for (int i = 0; i < pvec.size(); i++) { for (int j = 0; j < tvec.size(); j++) { int g = GCD(pvec[i], tvec[j]); ll t1 = pvec[i] / g; ll t2 = tvec[j] / g; ptset.insert(make_pair(t1,t2)); } } for (int i = 0; i < queries.size(); i++) { bool findone = false; for (int e1 = 0; e1 < NE;e1++) { for (int e2 = 0; e2 < NE;e2++) { if (e1 == e2) continue; ll t1 = evec[e1]*queries[i].first; ll t2 = evec[e2]*queries[i].second; ll g = GCD(t1, t2); t1 /= g; t2 /= g; if (ptset.find(make_pair(t1,t2))!=ptset.end()) { fout << endl << "Yes"; findone = true; break; } } if (findone) break; } if (!findone) { fout << endl << "No"; } } } void run() { FILE* fp = freopen("in.txt", "r", stdin); ofstream fout("out.txt"); int Cases = 0; scanf("%d", &Cases); for (int time = 0; time < Cases; time++) { cin >> NP >> NE >> NT; pvec.resize(NP); evec.resize(NE); tvec.resize(NT); for (int i = 0; i < NP; i++) { cin >> pvec[i]; } for (int i = 0; i < NE; i++) { cin >> evec[i]; } for (int i = 0; i < NT; i++) { cin >> tvec[i]; } cin >> M; queries.resize(M); for (int i = 0; i < M; i++) { cin >> queries[i].first >> queries[i].second; } fout << "Case #" << (time + 1) << ": "; SingleProcess(fout); fout << endl; std::cout << time << endl; } fclose(fp); fout.close(); } }; class PC { public: PC(){} ll N; vector<ll> primes; set<ll> primeSet; map<ll, bool> winMap; void predefine() { ll UPPER = 32000000; for (int i = 2; i < UPPER; i++) { bool findone = false; for (int j = 0; j < primes.size(); j++) { if (primes[j] * primes[j]>i) break; if (i%primes[j] == 0) { findone = true; break; } } if (!findone) { primes.push_back(i); primeSet.insert(i); } } } bool isGNumber(ll num) { ll ss = 0; while (num > 0) { ss += num % 10; num = num / 10; } if (ss == 1) return true; for (int i = 0; i < primes.size(); i++) { if (primes[i]>ss) return false; if (primes[i] == ss) return true; } return false; } bool DFS(ll num) { if (winMap.find(num) != winMap.end()) return winMap[num]; if (isGNumber(num)) return false; if (primeSet.find(num) != primeSet.end()) return true; ll upper = sqrt(num) + 1; ll temp = num; for (int i = 0; i < primes.size(); i++) { if (primes[i]>=upper) break; if (temp%primes[i] == 0) { ll t1 = primes[i]; while (temp%t1 == 0) t1 *= primes[i]; t1 /= primes[i]; temp /= t1; if (DFS(num/t1) == false) { winMap[num] = true; return true; } } } //留下来的也是质数,不是1就测试num/temp if (temp > 1) { if (DFS(num / temp) == false) { winMap[num] = true; return true; } } winMap[num] = false; return false; } void SingleProcess(ofstream& fout) { //winMap.clear(); if (DFS(N)) { fout << "Laurence"; } else { fout << "Seymour"; } } void run() { FILE* fp = freopen("in.txt", "r", stdin); ofstream fout("out.txt"); int Cases = 0; scanf("%d", &Cases); predefine(); for (int time = 0; time < Cases; time++) { cin>>N; fout << "Case #" << (time + 1) << ": "; SingleProcess(fout); fout << endl; std::cout << time << endl; } fclose(fp); fout.close(); } }; class PD { public: PD(){} string S; ll MODE = 1e9 + 7; vector<vector<ll>> C; void preDefine() { C.resize(501, vector<ll>(501, 0)); for (int i = 0; i < 501; i++) { for (int j = 0; j <= i; j++) { if (j == 0) C[j][i] = 1; else if (i == j) C[j][i] = 1; else C[j][i] = C[j - 1][i - 1] + C[j][i-1]; C[j][i] %= MODE; } } } struct SingleWord { char word; ll num; //map<pair<ll, ll>, ll> pairs; vector<vector<ll>> pairs; SingleWord(){ word = '0'; num = 0;} }; vector<SingleWord> wordvec; void SingleProcess(ofstream& fout) { wordvec.clear(); wordvec.resize(S.length()); for (int i = S.length()-1; i>=0; i--) { if (S[i] == 'd') { wordvec[i].word = 'd'; wordvec[i].num = 1; for (int j = i + 1; j < S.length(); j++) { if (S[j] == 'a') wordvec[i].num += wordvec[j].num; } wordvec[i].num %= MODE; } else if (S[i] == 'c') { wordvec[i].pairs.clear(); wordvec[i].pairs.resize(251, vector<ll>(251, 0)); int ct = 0; int dt = 0; for (int j = i + 1; j < S.length(); j++) { if (S[j] == 'c') ct++; else if (S[j] == 'd') { //以j为起点'd'; dt = 0; //先算以j为终点的cd,pair for (int kc = min(ct,249); kc >= 0; kc--) { ll t = C[kc][ct] * wordvec[j].num%MODE; wordvec[i].pairs[kc+1][1] += t; } //再算以j后面的k为终点的cd,pair for (int k = j + 1; k < S.length(); k++) { if (S[k] == 'd') //以这个'd'为终点 { for (int kc = min(ct,249); kc >= 0; kc--) { for (int kd = min(dt,248); kd >= 0; kd--) { ll t = C[kc][ct] * C[kd][dt] % MODE *wordvec[k].num%MODE; wordvec[i].pairs[kc + 1][kd+2] += t; } } dt++; } } } } } else if (S[i] == 'b') { wordvec[i].pairs.clear(); wordvec[i].pairs.resize(251, vector<ll>(251, 0)); //每个b点把后面的cdpair 综合起来,这样a过来查到b就不用往后查了 for (int j = i + 1; j < S.length(); j++) { if (S[j] == 'c') { for (int t1 = 0; t1 < 251;t1++) { for (int t2 = 0; t2 < 251; t2++) { wordvec[i].pairs[t1][t2] += wordvec[j].pairs[t1][t2]; wordvec[i].pairs[t1][t2] %= MODE; } } } } } else if (S[i] == 'a') { //查找所有以这个a为起点的abpair; int ta = 0; for (int j = i + 1; j < S.length(); j++) { if (S[j] == 'a') { ta++; } else if (S[j] == 'b') { //以这个b为起点 //先算以这个b为终点 int tb = 0; ll tot = 0; for (int ka = min(ta,249); ka >= 0; ka--) { //找后面所有能匹配的cdpair tot += wordvec[j].pairs[ka + 1][1] * C[ka][ta] % MODE; } wordvec[i].num += tot; //再算以这个b为起点,以后面的b为终点 tb = 0; for (int k = j + 1; k < S.length(); k++) { if (S[k] == 'b') { tot = 0; for (int ka = min(ta,249); ka >= 0; ka--) { for (int kb = min(tb,248); kb >= 0; kb--) { tot += C[kb][tb] * C[ka][ta] % MODE*wordvec[k].pairs[ka+1][kb+2]%MODE; } } wordvec[i].num += tot; wordvec[i].num %= MODE; tb++; } } } } } } ll total = 0; for (int i = 0; i < S.length(); i++) { if (S[i] == 'a') { total += wordvec[i].num; total %= MODE; } } fout << total; return; } void run() { FILE* fp = freopen("in.txt", "r", stdin); ofstream fout("out.txt"); int Cases = 0; scanf("%d", &Cases); preDefine(); for (int time = 0; time < Cases; time++) { char ch[1024]; cin >> ch; S = ch; fout << "Case #" << (time + 1) << ": "; SingleProcess(fout); fout << endl; std::cout << time << endl; } fclose(fp); fout.close(); } }; int main() { //PA p; //PB p; //PC p; PD p; p.run(); return 0; }
8649
相关文章推荐
- 谷歌中国算法比赛解题报告 APAC2017A
- 谷歌中国算法比赛解题报告 APAC2017B
- 谷歌中国算法比赛解题报告 APAC2014A
- 谷歌中国算法比赛解题报告 APAC2017C
- 谷歌中国算法比赛解题报告 APAC2015A
- 谷歌中国算法比赛解题报告 APAC2015C
- 谷歌中国算法比赛解题报告 APAC2015D
- 谷歌中国算法比赛解题报告 APAC2016A
- 谷歌中国算法比赛解题报告 APAC2016D
- 谷歌中国算法比赛结题报告 APAC2014B
- 2018年全国多校算法寒假训练营练习比赛(第二场)解题报告
- 2018年全国多校算法寒假训练营练习比赛(第四场)解题报告
- hdu 2819 Swap 二分图匹配 匈牙利算法 解题报告
- 校算法训练解题报告1(完整版)
- hdu 1285 确定比赛名次 解题报告
- 算法第二周解题报告
- 西南交大2011年第二次暑期集训比赛解题报告
- 算法实验课 lab1 解题报告
- Tarjan算法求解桥和边双连通分量(附POJ 3352 Road Construction解题报告
- 【LeetCode】Balanced Binary Tree 算法优化 解题报告