Google Code Jam 2014 Round1B
先のARCで運を使い果たしたので震えながら参加。
- -
A : The Repeater
- アルファベットの登場順を崩すような操作はできない
- なので与えられた文字列で、アルファベットの登場順が違うのがあったら勝てない
- 勝てるんだったら文字ごとに適当に個数を揃えてやれば良い
- こういうのを美しく書けるようになりたい人生でした
#include <iostream> #include <vector> #include <string> #include <cstdio> #include <algorithm> using namespace std; string conv(const string& s, vector<int>& v){ int cnt = 1; string res; res += s[0]; char c = s[0]; for(int i=1;i<s.size();i++){ if(c == s[i]) cnt++; else { v.push_back(cnt); cnt = 1; c = s[i]; res += c; } } v.push_back(cnt); return res; } int main(){ int T; cin >> T; for(int test=1;test<=T;test++){ int N; cin >> N; vector< vector<int> > v(N); bool won = true; string s, t; cin >> s; t = conv(s, v[0]); for(int i=1;i<N;i++){ cin >> s; string u = conv(s, v[i]); if(u != t) won = false; } if(!won){ printf("Case #%d: Fegla Won\n", test); continue; } int res = 0; for(int i=0;i<v[0].size();i++){ int add = 1000000; for(int j=1;j<=100;j++){ int sum = 0; for(int k=0;k<v.size();k++){ sum += abs(v[k][i]-j); } add = min(add, sum); } res += add; } printf("Case #%d: %d\n", test, res); } }
B : New Lottery Game
- あっ、このlargeやばいやつだ。と思ってまずはsmallを通した。
- largeは挑戦者が多いのに全く分からず、悲しい気持ちになってた。
- 先にC提出した後も分からなすぎて、暗殺教室9巻を読んでた程の体たらく
- 終了20分前くらいに、桁DPというワードが脳内に浮上したのでギリギリ通せた。
- 5重ループを書きながら、俺は何をしてるんだ…という気持ちになってた。
#include <iostream> #include <vector> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; int solveSmall(int A, int B, int K){ int res = 0; for(int i=0;i<A;i++){ for(int j=0;j<B;j++){ if((i&j) < K) res++; } } return res; } long long solveLarge(int A, int B, int K){ long long dp[2][2][2][2]; memset(dp, 0, sizeof(dp)); dp[0][1][1][1] = 1; for(int i=30;i>=0;i--){ int cur = i%2, next = 1-cur; memset(dp[next], 0, sizeof(dp[next])); for(int smallA=0;smallA<2;smallA++){ for(int smallB=0;smallB<2;smallB++){ for(int smallK=0;smallK<2;smallK++){ if(dp[cur][smallA][smallB][smallK] == 0) continue; for(int a=0;a<2;a++){ if(smallA && !(A&(1<<i)) && a == 1) continue; int nA = smallA ? ((A>>i)&1) == a : 0; for(int b=0;b<2;b++){ if(smallB && !(B&(1<<i)) && b == 1) continue; int nB = smallB ? ((B>>i)&1) == b : 0; if(smallK && !(K&(1<<i)) && a == 1 && b == 1) continue; int nK = smallK ? ((K>>i)&1) == (a&b) : 0; dp[next][nA][nB][nK] += dp[cur][smallA][smallB][smallK]; } } } } } } return dp[1][0][0][0]; } int main(){ int T; cin >> T; for(int test=1;test<=T;test++){ int A, B, K; cin >> A >> B >> K; printf("Case #%d: %lld\n", test, solveLarge(A, B, K)); } }
C : The Bored Traveling Salesman
- 悲しい気持ちでBから逃げてきたので、精神を安定させるためにまずsmallを通した。
- largeは…ある順で辿った時に、そこから残りを全部辿れるか判定できれば行けそう。
- validな奴を貪欲に辿っていくというパターン
- 各土地に往路チケットで行けるのは高々1回という仕様が地味に面倒
- 途中まで辿った段階で復路チケットを持ってる土地のリスト(A)と、往復使いきった土地のリスト(B)を持っておき、Aに属する土地から、Bに属する土地を通らずに全ての土地に行けるかを判定した。
- smallの解答と一致してそうに見えたので提出。通った。
#include <iostream> #include <vector> #include <string> #include <algorithm> #include <cstring> #include <cstdio> #include <stack> #include <queue> using namespace std; typedef vector< vector<int> > Graph; bool isValid(const Graph& g, const vector<int>& order){ stack<int> st; st.push(order[0]); for(int i=1;i<order.size();i++){ while(true){ if(st.empty()) return false; int pos = st.top(); bool ok = false; for(int j=0;j<g[pos].size();j++){ if(g[pos][j] == order[i]) ok = true; } if(ok){ st.push(order[i]); break; } else st.pop(); } } int n = g.size(); vector<int> visit(n, 0); for(int i=0;i<order.size();i++) visit[order[i]] = 1; queue<int> qu; while(!st.empty()){ qu.push(st.top()); st.pop(); } while(!qu.empty()){ int p = qu.front(); qu.pop(); for(int i=0;i<g[p].size();i++){ if(visit[g[p][i]]) continue; visit[g[p][i]] = 1; qu.push(g[p][i]); } } for(int i=0;i<n;i++) if(visit[i]==0) return false; return true; } int main(){ int T; cin >> T; for(int test=1;test<=T;test++){ int N, M; cin >> N >> M; Graph g(N); vector<string> vs(N); vector<int> state(N, 0); for(int i=0;i<N;i++) cin >> vs[i]; for(int i=0;i<M;i++){ int a, b; cin >> a >> b; g[a-1].push_back(b-1); g[b-1].push_back(a-1); } string res; int idx = 0; for(int i=0;i<N;i++) if(vs[idx] > vs[i]) idx = i; res = vs[idx]; vector<int> order; order.push_back(idx); vector<int> visit(N, 0); visit[idx] = 2; for(int i=0;i<g[idx].size();i++) visit[g[idx][i]] = 1; for(int i=1;i<N;i++){ idx = -1; order.push_back(0); for(int j=0;j<N;j++){ if(visit[j]!=1) continue; order.back() = j; if(isValid(g, order) && (idx==-1 || vs[idx] > vs[j])) idx = j; } order.back() = idx; res += vs[idx]; visit[idx] = 2; for(int i=0;i<g[idx].size();i++) visit[g[idx][i]] = max(1, visit[g[idx][i]]); } printf("Case #%d: %s\n", test, res.c_str()); } }
- -
Rank 105 : /oo/oo/oo/ Score 100, Penalty 2:17:30
small全部通れば通過くらいかと思ってましたが、通過ラインはそれより上でした。
こわい(´・ω・`)