ABC198 C - Compass Walking

■考えたこと
制約的に何歩で(X,Y)に行けるかを愚直に
シミュレーションする方針で解けると推測。

ACしたコードは下記。

using ll = long long;

int main() {
	int r, x, y;
	cin >> r >> x >> y;
	ll l = (ll)x * x + (ll)y * y;
	ll r2 = (ll)r * r;
	ll ans = 1;
	
	while (r2 * ans * ans < l) ans++;
	if (ans == 1) {
		if (r2 * ans * ans > l) ans++;
	}
	cout << ans << endl;
}

ABC317 C - Remembering the Days

■考えたこと
制約的に全探索と思った。
再帰で実装した。

ACしたコードは下記。

struct Edge {
	int to; ll cost;
	Edge(int to, ll cost) : to(to), cost(cost){}
};

int main() {
	int n, m;
	cin >> n >> m;
	vector<vector<Edge>> g(n);
	for (int i = 0; i < m; i++) {
		int a, b; ll c;
		cin >> a >> b >> c;
		--a; --b;
		g[a].push_back(Edge(b, c));
		g[b].push_back(Edge(a, c));
	}

	vector<bool> visited(n);
	ll ans = 0;
	auto dfs = [&](auto dfs, int v, ll c) -> void {
		visited[v] = true;
		ans = max(ans, c);
		for (auto nv : g[v]) {
			if (visited[nv.to]) continue;
			dfs(dfs, nv.to, c + nv.cost);
		}
		visited[v] = false;
	};

	for (int i = 0; i < n; i++) {
		dfs(dfs, i, 0);
	}
	cout << ans << endl;
}

ABC243 C - Collision 2

■考えたこと
y座標が同じ座標ごとにまとめれば見通しが良くなる。
まとめ後はx座標とR/Lのペアでデータを持ち、昇順でソートしてRLのペアが
存在するか判定すればOK。

ACしたコードは下記。

int main() {
	int n;
	cin >> n;
	vector<int> x(n), y(n);
	for (int i = 0; i < n; i++) cin >> x[i] >> y[i];
	string s;
	cin >> s;
	map<int, vector<pair<int, char>>> mp;
	for (int i = 0; i < n; i++) {
		mp[y[i]].push_back(make_pair(x[i], s[i]));
	}
	for (auto e : mp) {
		auto ps = e.second;
		sort(ps.begin(), ps.end());
		for (int i = 0; i < ps.size() - 1; i++) {
			if (ps[i].second == 'R' && ps[i + 1].second == 'L') {
				cout << "Yes" << endl;
				return 0;
			}
		}
	}
	cout << "No" << endl;
}

ABC341 C - Takahashi Gets Lost

■考えたこと

全探索をすると計算量O(HWN) = O(125 x 10^6)であり間に合うか心配だったが
この方針で実装してACした。

ACしたコードは下記。

int main() {
	int h, w, n;
	cin >> h >> w >> n;
	string t;
	cin >> t;
	vector<string> s(h);
	for (int i = 0; i < h; i++) cin >> s[i];

	int ans = 0;
	for (int hi = 0; hi < h; hi++) {
		for (int wj = 0; wj < w; wj++) {
			if (s[hi][wj] != '.') continue;
			int i = hi, j = wj;
			bool ok = true;
			for (int v = 0; v < n; v++) {
				if (t[v] == 'L') j -= 1;
				if (t[v] == 'R') j += 1;
				if (t[v] == 'U') i -= 1;
				if (t[v] == 'D') i += 1;

				if (i < 0 || i > h || j < 0 || j > w) ok = false;
				if (s[i][j] != '.') ok = false;
				if (!ok) break;
			}
			if (ok) ans++;
		}
	}

	cout << ans << endl;
}

ABC245 C - Choose Elements

■考えたこと
dpのような気がしたので入力例1の値で以下の表を書いてみた。

9 1
8 6
3 2
7 9
2 5
i \ j 0 1
0 true true
1 true true
2 true true
3 true false
4 false true

dpの定義は以下。
dp[i][j] = A[i][j]が条件を満たすかどうか。
dp[0][0] = dp[0][1] = true
dp[n - 1][0] または dp[n - 1][1] がtrueならYes。

以下はACしたコード。

int main() {
	int n, k;
	cin >> n >> k;
	vector<vector<int>> a(n, vector<int>(2));
	for (int i = 0; i < n; i++) cin >> a[i][0];
	for (int i = 0; i < n; i++) cin >> a[i][1];

	vector<vector<bool>> dp(n, vector<bool>(2, false));
	dp[0][0] = dp[0][1] = true;
	for (int i = 0; i < n - 1; i++) {
		for (int j = 0; j < 2; j++) {
			if (!dp[i][j]) continue;
			for (int l = 0; l < 2; l++) {
				if (abs(a[i + 1][l] - a[i][j]) <= k) {
					dp[i + 1][l] = true;
				}
			}
		}
	}
	
	for (int j = 0; j < 2; j++) {
		if (dp[n - 1][j]) {
			cout << "Yes" << endl;
			return 0;
		}
	}
	cout << "No" << endl;
}

ABC318 C - Blue Spring

■考えたこと

問題文を読んでも解法が思いつかなかった。

とりあえず入力例1で周遊パスを買っていったときの様子を紙に書いてみた。


1日周遊パスは2枚セットで10円で販売されているので各セット購入したとすると

・0セット:7 + 1 + 6 + 3 + 6 = 23円

・1セット:(10 x 1) + (0 + 1 + 0 + 3 + 6) = 20円 ← 料金が高い日順に周遊パスを割り当て

・2セット:(10 x 2) + (0 + 1 + 0 + 0 + 0) = 21円

・3セット:(10 x 3) + (0 + 0 + 0 + 0 + 0) = 30円

となる。

ここまで書き出すと3セット以降は料金が高くなっていくだけなので

試す必要がないことが分かった。

つまり5日間すべてを周遊パスで割り当てするためには3セットで十分。

これは N / D の切り上げ (以降k) で計算できる。 

制約的にkセット試せば間に合うと推測。

後はkセット購入した場合の合計料金をどう計算するかだが、下記を書いて

累積和でいけそうと推測。

f : 1   3   6     6    7

s : 0   1   4   10  16  23


以下はACしたコード。

using ll = long long;

int main() {
  int n, d, p;
  cin >> n >> d >> p;
  vector f(n);
  for (int i = 0; i < n; i++) cin >> f[i];
  sort(f.begin(), f.end());

  vector s(n + 1);
  for (int i = 0; i < n; i++) {
    s[i + 1] = s[i] + f[i];
  }

  int sd = (n + d - 1) / d;
  
  const ll INF = 1e18;
  ll ans = INF;
  for (ll i = 0; i <= sd; i++) {
    ll sum = 0;
    if (n - i * d > 0) sum += s[n - i * d];
    sum += p * i;
    ans = min(ans, sum);
  }
  cout << ans << endl;
}


ABC325 C - Sensors

■考えたこと

蟻本のLake Counting (POJ No.2386) と同じ問題。

とりあえずdfsで連結しているセンサーをなめていき

(訪れたセンサーはtrueにしておく) 再帰終了後、カウントを足すという方針で解いた。

ACしたコードは下記。

const int di[] = { 1, 0, -1, 0, 1, 1, -1, -1 };
const int dj[] = { 0, 1, 0, -1, 1, -1, 1, -1 };

int main() {
	int h, w;
	cin >> h >> w;
	vector<string> s(h);
	for (int i = 0; i < h; i++) cin >> s[i];

	vector<vector<bool>> visited(h, vector<bool>(w));
	auto dfs = [&](auto dfs, int i, int j) -> void {
		visited[i][j] = true;
		for (int v = 0; v < 8; v++) {
			int ni = i + di[v];
			int nj = j + dj[v];
			if (ni < 0 || ni >= h || nj < 0 || nj >= w) continue;
			if (visited[ni][nj]) continue;
			if (s[ni][nj] != '#') continue;
			dfs(dfs, ni, nj);
		}
	};

	int ans = 0;
	for (int i = 0; i < h; i++) {
		for (int j = 0; j < w; j++) {
			if (s[i][j] != '#') continue;
			if (visited[i][j]) continue;
			dfs(dfs, i, j);
			ans++;
		}
	}

	cout << ans << endl;
}