ooooo--- 109th. 1962 -> 2108(+146).
Hello 2018 できた.
A. Modular Exponentiation
問題概要
を出力せよ.
解法
が より大きければ mod は無視してよい.
余裕をもって を出力すれば十分.
ソース
#include <bits/stdc++.h> using namespace std; int main() { int N, M; cin >> N >> M; int base = 1; for(int i = 0; i < min(N, 30); i++) base *= 2; cout << M % base << endl; }
B. Christmas Spruce
問題概要
頂点の根付き木が与えられる.
すべての葉以外の頂点が, つ以上の葉を持つか判定せよ.
解法
判定をします.
.
ソース
#include <bits/stdc++.h> using namespace std; int main() { int64 N; vector< int > g[1000]; cin >> N; for(int i = 1; i < N; i++) { int x; cin >> x; g[--x].emplace_back(i); } for(int i = 0; i < N; i++) { if(g[i].empty()) continue; int sum = 0; for(auto& j : g[i]) if(g[j].empty()) ++sum; if(sum < 3) { cout << "No" << endl; return (0); } } cout << "Yes" << endl; }
C. Party Lemonade
問題概要
種類のボトルがある. ボトル には のレモネードが入っていて, コストは である.
以上のレモネードを買うための最小コストを求めよ.
解法
まず各 について, ちょうど容量 のレモネードを買うための最小コストを求める. これは雰囲気で min をとるとできる.
次に 以上のレモネードを買うための最小コストを求める. を上の bit からみていって, 基本的には が立ってる bit の容量は買う必要があるが, ある bit で余分に買ってもよくてこのときそれより下の bit の購入は不要になる. 余分に買う bit 位置を全探索.
なんか考察ミスや実装ミスが不安だけど, お祈りをすると通る. .
ソース
#include <bits/stdc++.h> using namespace std; using int64 = long long; const int64 INF = 1LL << 61; int main() { int N, L; int64 C[33]; fill_n(C, 33, INF); cin >> N >> L; for(int i = 0; i < N; i++) { cin >> C[i]; } for(int i = 31; i >= 0; i--) C[i] = min(C[i], C[i + 1]); for(int i = 1; i < 33; i++) C[i] = min(C[i], C[i - 1] + C[i - 1]); int64 sum = 0, ret = INF; for(int i = 31; i >= 0; i--) { if((L >> i) & 1) { ret = min(ret, sum + C[i + 1]); sum += C[i]; } } cout << min(sum, ret) << endl; }
D. Too Easy Problems
問題概要
個の問題があって, 問題 は ms で解決できる.
試験の得点は, 個の問題 を解いたとすると の個数である. このとき ms の間に得られる最大の得点を求めよ.
解法
priority_queue を持ちながらえい.
まず 点を得るとき 問解くのが最善である. 問より多くの問題を解くのは時間がかかるだけ. またこのとき解く問題の候補は の問題のみ. の問題を解いても得点は得られない.
最短時間で 問解くためには, 候補の中から昇順で 個とるのが最適で, この和が 以下であれば 点を得れる.
が大きい順に全探索して, 条件を満たしたところが答え. 候補の問題の個数は の減少にともなって単調増加になっているため, priority_queue をもつといい感じに前の計算結果を利用できて .
ソース
#include <bits/stdc++.h> using namespace std; using int64 = long long; int main() { int N, T; scanf("%d %d", &N, &T); vector< pair< int, int > > D[200001]; for(int i = 0; i < N; i++) { int x, y; scanf("%d %d", &x, &y); D[x].emplace_back(y, i); } priority_queue< pair< int, int > > que; int64 in = 0; for(int i = N; i >= 0; i--) { for(auto &p : D[i]) { que.emplace(p); in += p.first; } while(que.size() > i) { in -= que.top().first; que.pop(); } if(que.size() == i && in <= T) { printf("%d\n%d\n", i, i); while(que.size()) { printf("%d ", que.top().second + 1); que.pop(); } return (0); } } }
E. Logical Expression
問題概要
わかりやすいので原文を読んで♡
解法
DP.
- Emin[bit] := 真理値表が bit のとき, E をつくるときの最小の文字列
- Tmin[bit] := 真理値表が bit のとき, T をつくるときの最小の文字列
- Fmin[bit] := 真理値表が bit のとき, F をつくるときの最小の文字列
生成規則は問題文に書かれているため, 遷移もそれに従って書くとできる. くらい.
ソース
本番のとき無理全探索をしてて嵌ってた.
#include <bits/stdc++.h> using namespace std; string Emin[256], Tmin[256], Fmin[256]; bool chmin(string &a, string b) { if(a.empty() || a.size() > b.size() || (a.size() == b.size() && b < a)) { a = b; return (true); } return (false); } int main() { fill_n(Emin, 256, string(1000, '~')); fill_n(Tmin, 256, string(1000, '~')); fill_n(Fmin, 256, string(1000, '~')); Fmin[0b00001111] = "x"; Fmin[0b00110011] = "y"; Fmin[0b01010101] = "z"; bool update = true; while(update) { update = false; for(int i = 0; i < 256; i++) { update |= chmin(Fmin[i ^ 255], "!" + Fmin[i]); update |= chmin(Fmin[i], "(" + Emin[i] + ")"); update |= chmin(Emin[i], Tmin[i]); update |= chmin(Tmin[i], Fmin[i]); for(int j = 0; j < 256; j++) { update |= chmin(Emin[i | j], Emin[i] + "|" + Tmin[j]); update |= chmin(Tmin[i & j], Tmin[i] + "&" + Fmin[j]); } } } int N; cin >> N; while(N--) { string bit; cin >> bit; int bits = 0; for(int i = 0; i < 8; i++) if(bit[i] == '1') bits |= 1 << (7 - i); cout << Emin[bits] << endl; } }