AtCoder趣味

【AtCoder ABC001】C++の解答例・解法メモ

AtCoder

ABC001 (AtCoder Beginner Contest) のA、B、C、D問題の自分の解答と解法のメモです。
ソースコードはsusisobのGitHubにあります。main.cppが解答です。

すしそ
すしそ

C++と競プロ勉強しはじめて1ヶ月もない初心者なので、間違いがあったらすみません!
教えていだだけると嬉しいです!!

AtCoder/past/abc001 at main · susisob/AtCoder
AtCoderの解答とか. Contribute to susisob/AtCoder development by creating an account on GitHub.

A – 積雪深差

問題:https://atcoder.jp/contests/abc001/tasks/abc001_1

入力を受け取って差を出力するだけなので超簡単です。

#include <bits/stdc++.h>
using namespace std;

int main(){
	int H1, H2;
	cin >> H1 >> H2;
	cout << H1 - H2 << endl;
}

B – 視程の通報

問題:https://atcoder.jp/contests/abc001/tasks/abc001_2

入力された距離に対して条件分岐で視程を変化させます。
範囲外の数値は入力されないという制約があるので、5kmと6kmの間とかは考えなくてすみます。

ただ、問題文の条件では単位がkmなのに対して、入力される値は単位がmなので注意が必要です。
小数点の演算は誤差が出やすいと思ったので、条件の方をmに変換して実装しました。

あとは、出力を2桁に揃える必要があります。

#include <bits/stdc++.h>
using namespace std;

int main(){
	int m;
	cin >> m;
	int vv;
	if (m < 100){
		vv = 0;
	}
	else if (100 <= m && m <= 5000){
		vv = m * 10;
	}
	else if (6000 <= m && m <= 30000){
		vv = m + 50000;
	}
	else if (35000 <= m && m <= 70000){
		vv = (m - 30000) / 5 + 80000;
	}
	else if (m > 70000){
		vv = 89000;
	}
	vv  /= 1000;
	cout << setw(2) << setfill('0') << vv << endl;
}

C – 風力観測

問題:https://atcoder.jp/contests/abc001/tasks/abc001_3

これも条件分岐の問題です。ただ、条件が多すぎて大変なので、方位だけ22.5度ずつ変わるという規則性を利用してちょっと楽しました。

風力は条件に規則性が見えなかったのでそのまま書いています。
風力が0のときに方位がCになるということに注意してください。

風力は入力された風程から風速を計算して求めます。
具体的には風程[m]を60[s]で割って、少数第二位を四捨五入します
そのまま実装すると小数点の演算になって、条件比較も小数点同士になり、難しくなると思います。

すしそ
すしそ

何も考えず、60で割って四捨五入したら全然ACになりませんでした。
四捨五入の部分は小数点があったほうが計算しやすいですが、数値の比較は整数のほうがやりやすいので条件を10倍してすべて整数にしています。
単位が[m * 10/s]とかになってしまいますが、競技プログラミングなので許して。

#include <bits/stdc++.h>
using namespace std;

int main(){
	int deg, dis;
	cin >> deg >> dis;
	string dir;
	vector<string> dirList = {"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"};
	dir = "N";
	deg *= 10;
	for (int i=0; i < 16; i++){
		if (2250 * i - 1125 <= deg && deg < 2250 * i + 1125){
			dir = dirList.at(i);
		}
	}
	int W;
	int v = round(dis / 6.0);
	if (0 <= v && v <= 2){
		W = 0;
	}
	else if (3 <= v && v <= 15){
		W = 1;
	}
	else if (16 <= v && v <= 33){
		W = 2;
	}
	else if (34 <= v && v <= 54){
		W = 3;
	}
	else if (55 <= v && v <= 79){
		W = 4;
	}
	else if (80 <= v && v <= 107){
		W = 5;
	}
	else if (108 <= v && v <= 138){
		W = 6;
	}
	else if (139 <= v && v <= 171){
		W = 7;
	}
	else if (172 <= v && v <= 207){
		W = 8;
	}
	else if (208 <= v && v <= 244){
		W = 9;
	}
	else if (245 <= v && v <= 284){
		W = 10;
	}
	else if (285 <= v && v <= 326){
		W = 11;
	}
	else if (327 <= v){
		W = 12;
	}
	if (W == 0){
		dir = "C";
	}
	cout << dir << " " << W << endl;
}

D – 感雨時刻の整理

問題:https://atcoder.jp/contests/abc001/tasks/abc001_4

雨が降った時間を整理する問題です。

時間を扱う問題のため、入力、出力の形式が結構特殊なので文字列で受けて、整数に直します。
その後、雨の開始時刻は直前の5分、終了時刻は直後の5分に調整します。
直前に合わせる場合は00分で止まるので問題ないですが、
直後に合わせる場合は60分から00分になおす必要があるので、時間に繰り上げて分は00に直します。

ここで開始時刻、終了時刻をpairで扱っていると、sortで開始時刻の順に並べて、開始時刻が同じ場合は終了時刻が早い順に並べられます。

最後に合成できる時間は合成して出力することになります。
早い順になったvectorから要素を取り出してメモリにいれて行きます。
今のメモリの終了時刻が次の要素の開始時刻と等しい場合は次の要素の終了時刻でメモリの終了時刻を更新します。(①)
次の要素の開始時刻がメモリの終了時刻より早い場合は、次の要素の終了時刻がメモリの終了時刻より遅い場合にだけ、メモリの終了時刻を更新します。(②)
時刻に重なりがない場合は、今の時刻を出力してからメモリを新しく更新します。(③)

出力のフォーマットに気をつけてください。

すしそ
すしそ

汚い図でごめん…

#include <bits/stdc++.h>
using namespace std;

int main(){
	int N;
	cin >> N;
	vector<pair<int, int>> t_list;
	for (int i=0; i<N; i++){
		string t;
		cin >> t;
		int t_start = stoi(t.substr(0, 4));
		int t_end = stoi(t.substr(5, 4));
		while (t_start % 5 != 0){
			t_start--;
		}
		while (t_end % 5 != 0){
			t_end++;
			if (t_end % 100 == 60){
				t_end += 100;
				t_end -= 60;
			}
		}
		t_list.push_back({t_start, t_end});
	}
	sort(t_list.begin(), t_list.end());
	int ans_start, ans_end;
	for (int i=0; i<N; i++){
		if (i == 0){
			ans_start = t_list.at(i).first;
			ans_end = t_list.at(i).second;
		}
		else {
			if (t_list.at(i).first == ans_end){
				ans_end = t_list.at(i).second;
			}
			else if (t_list.at(i).first < ans_end){
				if (t_list.at(i).second > ans_end){
					ans_end = t_list.at(i).second;
				}
			}
			else{
				cout << setw(4) << setfill('0') << ans_start << "-" << setw(4) << setfill('0') << ans_end << endl;
				ans_start = t_list.at(i).first;
				ans_end = t_list.at(i).second;
			}
		}
		if (i == N-1){
			cout << setw(4) << setfill('0') << ans_start << "-" << setw(4) << setfill('0') << ans_end << endl;
		}
	}
}

まとめ

最初のabcだからか簡単でしたが、条件分岐とか小数点の演算が多かったですね。
特にC問題の四捨五入からの数値比較で誤差がでまくって大変でした。
D問題はsortして、条件の整理さえすればすんなり解けました。

コメント

タイトルとURLをコピーしました