Bondo416さんのデンソークリエイトプログラミングコンテスト2022(AtCoder Beginner Contest 239)での成績:1609位
— ボンド@競プロ (@bond_cmprog) February 19, 2022
パフォーマンス:1213相当
レーティング:1548→1518 (-30) :(#AtCoder #デンソークリエイトプログラミングコンテスト2022(ABC239) https://t.co/fQWWvEdILA
A - Horizon
問題文の数式をそのまま求める
void solve(){ ll x; cin >> x; printf("%.12lf\n", sqrt(x * (x + 12800000))); }
B - Integer Division
負の数のときの処理に気をつける
void solve(){ ll X; cin >> X; cout << floor_div(X, 10) << endl; }
C - Knight Fork
問題文の図にある通り、あり得る箇所は $ (x1, y1) $ の周り8通りと $ (x2, y2) $ の周り8通りなのでこれを全探索し、一致する座標があるかどうかを判定する
void solve(){ ll x1, x2, y1, y2; cin >> x1 >> y1 >> x2 >> y2; int dx[8] = {1, 2, 2, 1, -1, -2, -2, -1}; int dy[8] = {2, 1, -1, -2, 2, 1, -1, -2}; bool ok = false; REP(i,8){ ll nx1 = x1 + dx[i]; ll ny1 = y1 + dy[i]; REP(j,8){ ll nx2 = x2 + dx[j]; ll ny2 = y2 + dy[j]; if(nx1 == nx2 and ny1 == ny2) ok = true; } } cout << (ok ? "Yes" : "No") << endl; }
D - Prime Sum Game
高橋くんが選んだ数字に対し、青木くんが選べるどの数字を使っても素数にできないとき、高橋くんはその数を選べばいい
そのような数字がないときは青木くんが必ず勝つ
void solve(){ int A, B, C, D; cin >> A >> B >> C >> D; SieveOfEratosthenes<int> sieve(222); bool ok = false; for(int i=A;i<=B;i++){ bool ok2 = true; for(int j=C;j<=D;j++){ if(sieve.is_prime[i+j]) ok2 = false; } ok |= ok2; } cout << (ok ? "Takahashi" : "Aoki") << endl; }
E - Subtree K-th Max
ある頂点において、その頂点の部分木に含まれる頂点に書かれている数字の大きい順に20個求めればいい
DFSをし、葉のほうから順に上位20件の数字を更新していけばいい
void solve(){ int N, Q; cin >> N >> Q; vector<ll> X(N); REP(i,N) cin >> X[i]; vector<vector<int>> g(N); REP(i,N-1){ int a, b; cin >> a >> b; --a, --b; g[a].emplace_back(b); g[b].emplace_back(a); } vector<multiset<int>> dp(N); REP(i,N) dp[i].insert(X[i]); vector<int> idx(N); iota(ALL(idx), 0); auto dfs = [&](auto && self, int v, int par) -> void{ for(auto nv : g[v]){ if(nv == par) continue; self(self, nv, v); for(auto &x : dp[nv]){ if(dp[v].size() < 20) dp[v].insert(x); else{ dp[v].insert(x); dp[v].erase(dp[v].begin()); } } } return; }; dfs(dfs, 0, -1); REP(i,Q){ int v, k; cin >> v >> k; --v, --k; for(auto itr=dp[v].rbegin();itr!=dp[v].rend();itr++){ if(k == 0){ cout << *itr << endl; break; } k--; } } }
F - Construct Highway
$ \sum D_i = 2(N-1) $ の時の場合を考える
連結成分ごとに残りいくつの辺を繋げることができるかを管理する
このとき、残り2以上の連結成分があれば残り1の連結成分との辺を結んでいく
最終的に残り1の連結成分がちょうど2つ残っていれば条件を満たす木を構築することができる
void solve(){ int N, M; cin >> N >> M; vector<int> D(N); REP(i,N) cin >> D[i]; UnionFind uf(N); REP(i,M){ int a, b; cin >> a >> b; --a, --b; D[a]--, D[b]--; uf.unite(a, b); } vector<vector<int>> v(N); REP(i,N){ if(D[i] < 0){ cout << -1 << endl; return; } REP(j,D[i]) v[uf.root(i)].emplace_back(i); } vector<int> cnt1; vector<vector<int>> cnt2; REP(i,N){ if(v[i].size() == 1) cnt1.emplace_back(v[i][0]); else if(v[i].size() > 1) cnt2.emplace_back(v[i]); } vector<pair<int, int>> ans; for(auto vec : cnt2){ REP(i,(int)vec.size()-1){ if(cnt1.empty()){ cout << -1 << endl; return; } uf.unite(vec[i], cnt1.back()); ans.emplace_back(vec[i], cnt1.back()); cnt1.pop_back(); } cnt1.emplace_back(vec.back()); } if(cnt1.size() != 2){ cout << -1 << endl; return; } uf.unite(cnt1[0], cnt1[1]); ans.emplace_back(cnt1[0], cnt1[1]); if(uf.size(0) != N){ cout << -1 << endl; return; } for(auto [a, b] : ans) cout << a+1 << " " << b+1 << endl; }