AtCoder

ABC367 E問題(Permute K times)を解く

AtCoder_ABC367_E

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

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

E問題 Permute K times(Difficulty : 1370)

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

ABC367 E問題 Permute K times

ダブリングを適用して計算量を下げることができます。AtCoder Problems による Difficulty は 1370 でした。

解答案

繰り返す回数 $K$ の制約が $0 \leqq K \leqq 10^{18}$ と非常に大きく、定義通り計算していては間に合いません。

1回操作した後にもう1回操作をすると2回操作したことになります。2回操作した後にもう2回操作をすると4回操作したことになります。dp[i][j] を $2^i$ 回操作した後の要素 $j$ の場所とします。これは、以下の手順で求めることができます。

dp[i + 1][j] = dp[i][dp[i][j]]

十分な大きさの $i$ に対して、dp[i][j] を求めておくと、$K$ のセットされているビットについて演算します。例えば、11回後であれば、1回後→2回後→8回後のように場所を求めることができます。

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

上記の漸化式に従いdp[i][j] を計算します。dp[0][j] は、x[j] となります(21ー29行目)。

dp[i][j] を使って、k のビットに従い、行き先を求めます(33ー38行目)。最後に要素のインデックスから配列 a に変換して出力します。

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

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

typedef unsigned long long int ull;

int main()
{
	int n;
	ull k;
	cin >> n >> k;
	vector<ull> x(n);
	for (int i = 0; i < n; ++i) {
		cin >> x[i];
		--x[i];
	}
	vector<ull> a(n);
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
	}

	vector<vector<int>> dp(62, vector<int>(n, 0));
	for (int i = 0; i < n; ++i) {
		dp[0][i] = x[i];
	}
	for (int i = 0; i + 1 < 62; ++i) {
		for (int j = 0; j < n; ++j) {
			dp[i + 1][j] = dp[i][dp[i][j]];
		}
	}

	vector<int> result(n);
	for (int i = 0; i < n; ++i) {
		result[i] = i;
		for (int j = 0; j < 62; ++j) {
			if ((k & (1ULL << j)) != 0) {
				result[i] = dp[j][result[i]];
			}
		}
		result[i] = a[result[i]];
	}

	for (int i = 0; i < n; ++i) {
		cout << result[i] << " \n"[i == n - 1];
	}

	return 0;
}

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

Python プログラム例(ABC367E)

Python版も基本的な考え方は同じです。

以下のプログラムは、「Python (CPython 3.11.4)」では、TLE判定となり、「Python (PyPy 3.10-v7.3.12)」で、AC判定となりました。

"""AtCoder Beginner Contest 367 E"""
n, k = map(int, input().split())
x = list(map(int, input().split()))
for i in range(n):
    x[i] -= 1
a = list(map(int, input().split()))

dp = [[0 for _ in range(n)] for _ in range(62)]
for i in range(n):
    dp[0][i] = x[i]
for i in range(61):
    for j in range(n):
        dp[i + 1][j] = dp[i][dp[i][j]]

result = [0] * n
for i in range(n):
    result[i] = i
    for j in range(62):
        if (k & (1 << j)) != 0:
            result[i] = dp[j][result[i]]
    result[i] = a[result[i]]

print(*result)

最後に

この問題は、ダブリングを使うことは分かりましたが、64ビットの整数を32ビットで演算していて、この間違いを時間内に気付くことができませんでした。残念です。

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

COMMENT

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

CAPTCHA