AtCoder

ABC005 D問題(おいしいたこ焼きの焼き方)を解く

AtCoder_ABC005_D

AtCoder が提供しているABC(AtCoder Beginner Contest)005 D問題をC++で解いてみました。ABC005は、2014年3月22日21:00に実施されました。

AtCoder の紹介はこちらに、プログラミングの方針はこちらに記事があります。

D問題 おいしいたこ焼きの焼き方(Difficulty : 1447(参考値))

問題の詳細は、リンク先をご覧ください。

ABC005 D問題 おいしいたこ焼きの焼き方

2次元の累積和を求めて準備しておきます。AtCoder Problems による Difficulty は 1447(参考値)でした。

解答案

C++ プログラム例(ABC005D)

たこ焼き器内のすべての長方形領域について、美味しさを事前に計算しておくことで、計算量を削減できます。このために2次元の累積和を利用します。

プログラムの補足です。

  • 2次元の累積和を計算します(15ー23行目)。
  • 累積和を用いて、すべての部分長方形の面積に対する美味しさの最大値 m を計算します(25ー36行目)。
  • その面積より小さい面積が持つ美味しさの最大値で、その面積の美味しさの最大値を更新します(38ー42行目)。
  • 各店員が焼けるたこ焼きの最大美味しさを出力します(49行目)。

以下が、C++プログラムです。累積和の定番コードの背景色を変更しました。

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

int main()
{
	int n;
	cin >> n;
	vector<vector<int>> d(n, vector<int>(n));
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			cin >> d[i][j];
		}
	}

	vector<vector<int>> sum_d(n + 1, vector<int>(n + 1, 0));
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			sum_d[i + 1][j + 1] = sum_d[i][j + 1];
			sum_d[i + 1][j + 1] += sum_d[i + 1][j];
			sum_d[i + 1][j + 1] -= sum_d[i][j];
			sum_d[i + 1][j + 1] += d[i][j];
		}
	}

	vector<int> m(50 * 50 * 1000 + 1, 0);
	for (int i1 = 0; i1 < n; ++i1) {
		for (int i2 = i1 + 1; i2 <= n; ++i2) {
			for (int j1 = 0; j1 < n; ++j1) {
				for (int j2 = j1 + 1; j2 <= n; ++j2) {
					int t = sum_d[i2][j2] - sum_d[i1][j2] - sum_d[i2][j1] +
							sum_d[i1][j1];
					m[(i2 - i1) * (j2 - j1)] = max(m[(i2 - i1) * (j2 - j1)], t);
				}
			}
		}
	}

	int d_max = 0;
	for (int i = 0; i <= 50 * 50 * 1000; ++i) {
		d_max = max(m[i], d_max);
		m[i] = d_max;
	}

	int q;
	cin >> q;
	for (int i = 0; i < q; ++i) {
		int p;
		cin >> p;
		cout << m[p] << endl;
	}

	return 0;
}

AC(Accepted=正しいプログラム)と判定されました。

最後に

2次元の累積和は、基本的には1次元の累積和と同じ原理ですが、式が複雑に感じられます。テンプレートを活用して解決しました。

引き続き ABC の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA