CADDi 2018 for Beginnersに参加しました
CADDi 2018 for Beginnersに参加したので記録を残したいと思います.
今回のコンテストは、キャディ株式会社主催のABC/ARC形式のプログラミングコンテストで、レートが~1199までの人が参加できる初級者向けコンテストに参加しました。 要はいつものABC形式ですね。
問題のタイトルは以下のようになっています. 詳しい問題文は下のリンクから、公式のコンテストページでご確認ください.
- A - 12/22
- B - AtCoder Alloy
- C - Product and GCD
- D - Harlequin
A - 12/22
問題の概要
十進法表記でちょうど4桁の整数が与えられる. の十進法表記に何個の「2」が現れるかを求める.
解法
を文字列として受け取り、先頭から2があるかどうかをfor文で確認すれば良いです.
#include <iostream> #include <string> #include <vector> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <map> #include <stack> #include <queue> #include <set> #include <cstring> using namespace std; #define rep(i, a, b) for(int i = (int)a; i < (int)b; i++) int main(){ cin.tie(0); ios::sync_with_stdio(false); string N; cin >> N; int rsl = 0; rep(i, 0, N.size()) { if(N[i] == '2') rsl++; } cout << rsl << endl; }
B - AtCoder Alloy
問題の概要
長方形の板状の素材が枚ある. 番目の素材の縦の長さ、横の長さはそれぞれで与えられる. 縦の長さが、横の長さがの長方形の板を作りたい. 板を長方形の変に平行に切断することで、欲しい板を作ることができる素材は枚中何枚あるかを求める. ただし、素材は向きが決まっているため回転することができない.
解法
番目の素材を適切に切断することによって、縦の長さが、横の長さがの板を作ることができるとは、かつを満たすときです. したがって、この条件を満たす素材の個数をカウントしてあげればよいことになります.
#include <iostream> #include <string> #include <vector> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <map> #include <stack> #include <queue> #include <set> #include <cstring> using namespace std; #define rep(i, a, b) for(int i = (int)a; i < (int)b; i++) int main(){ cin.tie(0); ios::sync_with_stdio(false); int N, H, W; cin >> N >> H >> W; int A[N], B[N]; rep(i, 0, N) cin >> A[i] >> B[i]; int rsl = 0; rep(i, 0, N) { if(A[i] >= H and B[i] >= W) rsl++; } cout << rsl << endl; }
C - Product and GCD
問題の概要
がある. の値はわからないが、はわかっている.
このとき、の最大公約数として考えられるもののうち、最大値を求める.
解法
個の数列の積が与えられているので、を素因数分解します. 素因数分解した結果を、番目の素因数をとしたとき、
$$ P = p_1^{b_1} \times p_2^{b_2} \times \cdots \times p_m^{b_m} $$
と表せたとします. が個の数列の公約数になるのは、数列の各項が素因数の積でを作れるときです. 最大公約数はそのうち最大のものなので、共通の素因数を全て使って掛け合わせたものになります.
例えば、との最大公約数は共通の素因数が2つなので、それらの積で表される、が最大公約数になります.
したがって、Pの各素因数を先頭から順に個の数列の項に振り分けてあげれば良いことになります.
のとき、素因数2をにそれぞれ一つずつ、3もそれぞれ1つずつ振り分けることができます. 5は1つしかなく、3つの項に振り分けることができません. したがって、を作ることができ、最大公約数は6になります. (残った素因数5を適当にとかに振り分けても共通の素因数を他の項が持たないので最大公約数に影響を与えません.)
したがって、のとき、を各項に個振り分けていけば良いことになります.
素因数分解の部分は蟻本を参考にしました. 計算量はなので、間に合います.
#include <iostream> #include <string> #include <vector> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <map> #include <stack> #include <queue> #include <set> #include <cstring> using namespace std; #define rep(i, a, b) for(int i = (int)a; i < (int)b; i++) typedef long long ll; map<ll, ll> prime_factor(ll n) { map<ll, ll> res; for(ll i = 2; i * i <= n; i++) { while(n % i == 0) { ++res[i]; n /= i; } } if(n != 1) res[n] = 1; return res; } int main(){ cin.tie(0); ios::sync_with_stdio(false); ll N, P; cin >> N >> P; map<ll, ll> m = prime_factor(P); ll rsl = 1; for(map<ll, ll>::iterator itr = m.begin(); itr != m.end(); itr++ ){ if(itr->second >= N) rsl *= (pow(itr->first, itr->second / N)); } cout << rsl << endl; }
D - Harlequin
問題の概要
色のりんごがあり、番目の色のりんごは個ある. このとき、先攻、後攻にわかれて以下の行動を交互に行う.
- 1個以上のリンゴを選んで食べる. ただし、一度に選ぶリンゴは全て異なる色でなければならない.
最後のリンゴを食べた人を勝者とする. 先攻と後攻が最善を尽くすとき、どちらが勝つかを求める
解法
入力例1を例に考察してみます.
1番目のリンゴが1個、2番目のリンゴが2個あるとき、先攻は1番目のリンゴを1個食べれば、2番目のリンゴが2個残ります. このとき、後攻は2番目のリンゴを1個食べることしか選択肢がありません. 後攻が2番目のリンゴを一個食べた後は2番目のリンゴが1 個だけ残り、それを先攻が食べることで、先攻が勝利することができます.
毎ターン、各リンゴは最大でも1つしか減らないので、自分のターンにリンゴが奇数個ある場合、交互に1つずつ食べていくと最終的に自分が最後の一個を食べることができます. 逆に偶数個のときは、自分が最初にそのリンゴに手を出すと相手に最後の一個を食べられてしまいます.
1つでも奇数個のリンゴが存在すれば、そのリンゴだけを食べることで、全色のリンゴの個数を偶数個にすることができます. 全て偶数個になってしまったら、上で述べた理由から最後のリンゴを相手に食べられてしまうので、相手にその状況を作れた方が勝者となります.
したがって、各リンゴの個数のうち奇数のものが一つでも存在したら先攻が勝利します.
#include <iostream> #include <string> #include <vector> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <map> #include <stack> #include <queue> #include <set> #include <cstring> using namespace std; #define rep(i, a, b) for(int i = (int)a; i < (int)b; i++) typedef long long ll; int main(){ cin.tie(0); ios::sync_with_stdio(false); int N; cin >> N; int a[N]; int cnt_even = 0; rep(i, 0, N) { cin >> a[i]; if(a[i] % 2 == 0) cnt_even++; } if(cnt_even == N) cout << "second" << endl; else cout << "first" << endl; }
感想
パフォーマンス1600の順位26位という私にしては信じられないぐらいの結果でかなり嬉しいです.
C問題でWAを出さずにいたら1桁順位も狙え賞金をもらえたと思うと少し悔しいですが、久しぶりの全完で満足しています.
少し水色に近づいたので、これからも精進していき、一日でも早く「水色になるまでにやったこと」という記事をかけるように頑張っていきます.