AtCoder

ABC354 D問題(AtCoder Wallpaper)を解く

AtCoder_ABC354_D

AtCoder が提供しているABC(AtCoder Beginner Contest)354 D問題をC++とPythonで解いてみました。ABC354は、2024年5月18日21:00に実施されました。

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

D問題 AtCoder Wallpaper(Difficulty : 1259)

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

ABC354 D問題 AtCoder Wallpaper

2次元累積和で解くことができます。AtCoder Problems による Difficulty は 1259 でした。

解答案

ABC331 D問題解説記事)とほぼ同じ問題です。同じパターンが繰り返されるため、原点を左下とする関数を作るとプログラムがすっきりと書けます。

今回の問題は、4×2の赤枠で示したパターンが繰り返されます。

この赤枠の2次元累積和を計算します。この部分の面積を配列で表現すると以下になります。注)上下が逆になっているように見えます。値は2倍しています。

{{2, 1, 0, 1}, 
 {1, 2, 1, 0,}};

この面積の2次元累積和を求めると以下の配列となります。横方向にも縦方向にも配列をひとつ余分に取っています。

int s[3][5] = {
    {0, 0, 0, 0, 0},
    {0, 2, 3, 3, 4},
    {0, 3, 6, 7, 8}};

この2次元累積和を使うと、原点を左下とする長方形の黒い部分の面積が簡単に求まります。ABC331 D問題の公式解説の図で説明します。

この長方形に含まれる黒の面積は以下の関数 black で求めることができます。問題では、左下(0,0) から 右上 (i, j) に含まれる黒の面積となります。

typedef long long int ll;

ll black(ll i, ll j)
{
	ll result = 0;

	ll all = s[2][4]; // Aの面積
	ll ni = i / 4;
	ll nj = j / 2;
	result += all * ni * nj; // Aの面積×含まれている個数

	ll mi = i % 4;
	ll mj = j % 2;
	result += s[mj][4] * ni; // Bの面積×Bの個数
	result += s[2][mi] * nj; // Cの面積×Cの個数
	result += s[mj][mi]; // Dの面積を加える。

	return result;
}

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

この問題は、負の数が頂点になると計算が煩雑になるため、$x$ と $y$ に $10^9$ を加えておきます。$10^9$ は、2でも4でも割り切れるため、面積は変わりません。

上で説明した関数 black を使うと、以下の式で面積を求めることができます。

black(c, d) – black(a, d) – black(c, b) + black(a, b)

以下が、C++プログラムです。

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

typedef long long int ll;
#define OFFSET 1000000000LL;

int s[3][5] = {{0, 0, 0, 0, 0}, {0, 2, 3, 3, 4}, {0, 3, 6, 7, 8}};

ll black(ll i, ll j)
{
	ll result = 0;

	ll all = s[2][4];
	ll ni = i / 4;
	ll nj = j / 2;
	result += all * ni * nj;

	ll mi = i % 4;
	ll mj = j % 2;
	result += s[mj][4] * ni;
	result += s[2][mi] * nj;
	result += s[mj][mi];

	return result;
}

int main()
{
	ll a, b, c, d;
	cin >> a >> b >> c >> d;
	a += OFFSET;
	b += OFFSET;
	c += OFFSET;
	d += OFFSET;

	cout << black(c, d) - black(a, d) - black(c, b) + black(a, b) << endl;

	return 0;
}

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

Python プログラム例(ABC354D)

Python版も基本的な考え方は同じです。以下がプログラムです。

"""AtCoder Beginner Contest 354 D"""
OFFSET = 10 ** 9
s = [[0, 0, 0, 0, 0], [0, 2, 3, 3, 4], [0, 3, 6, 7, 8]]


def black(i, j):
    global s

    result = 0

    all_b = s[2][4]
    ni = i // 4
    nj = j // 2
    result += all_b * ni * nj

    mi = i % 4
    mj = j % 2
    result += s[mj][4] * ni
    result += s[2][mi] * nj
    result += s[mj][mi]

    return result


a, b, c, d = map(int, input().split())
a += OFFSET
b += OFFSET
c += OFFSET
d += OFFSET

print(black(c, d) - black(a, d) - black(c, b) + black(a, b))

こちらも「AC」と判定されました。

最後に

ABC331問題を解説する記事では、「次に見たときに解けるようになればと思います」と書いていました。似た問題をコンテストで解くことができました。私にとって、Diff 1259 は、コンテストで解けた問題の最高難易度でした。

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

COMMENT

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

CAPTCHA