公式解説

imoscon_c 解説

By
tyranno_gyaos

解法

問題を以下のように言い換える.以降ではこの言い換えた問題を解くことについて考える.

問題 - 言い換え

長さ 21052 \cdot 10^5 の非負整数列 XX が与えられます.
数列 XX に以下の操作を施すことですべての要素を 00 にすることができるか判定してください.
ただし,操作 33 はそれぞれ 11 回ずつしか行うことができません.行わなくても構いません.

  • 操作 11 : 任意の整数 i(1i199998)i (1 \leq i \leq 199998)11 つ選び,Xi,Xi+1,Xi+2X_i, X_{i+1}, X_{i+2} をそれぞれ 11 減らす
  • 操作 22 : 任意の整数 i(1i200000)i (1 \leq i \leq 200000)11 つ選び,XiX_i33 減らす
  • 操作 3.13.1 : 任意の整数 i(1i200000)i (1 \leq i \leq 200000)11 つ選び,XiX_i11 減らす
  • 操作 3.23.2 : 任意の整数 i(1i200000)i (1 \leq i \leq 200000)11 つ選び,XiX_i22 減らす
  • 操作 3.33.3 : 任意の整数 i(1i200000)i (1 \leq i \leq 200000)11 つ選び,XiX_i11 増やす

この言い換えは,もともとの問題文で与えられる数列 AA に関して,Xi=(X_i = (数列 AiA_i に含まれる ii の個数)) を満たすように数列 XX を構成することで,操作らが問題の条件と対応づけることができるので,正当である.

ここで,dpテーブルを考える.
... 記述中です!更新をお待ちください

回答例(C++)

#include<bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; i++)
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> vec(200'000, 0);
    rep(i, 3 * n + 2) {
        int x;
        cin >> x;
        vec[x - 1] += 1;
    }
    vector<int> pm = {0, -2, -1, -3, 1, -1, 0, -2};
    vector<vector<int>> trans = {
        {0, 1, 2, 3, 4, 5, 6, 7}, 
        {1, 3, 5, 7}, 
        {2, 3, 6, 7}, 
        {3, 7}, 
        {4, 5, 6, 7}, 
        {5, 7}, 
        {6, 7}, 
        {7}
    };
    vector<vector<vector<bool>>> dp(8, vector<vector<bool>>(200'001, vector<bool>(9, false)));
    dp[0][0][0] = true;
    rep(j, 200'000) {
        rep(i, 8) {
            rep(k, 9) {
                if (dp[i][j][k]) {
                    for (auto next : trans[i]) {
                        int now = vec[j] + pm[next] - pm[i] - k / 3 - k % 3;
                        if (now < 0) continue;
                        dp[next][j + 1][3 * (k % 3) + now % 3] = true;
                    }
                }
            }
        }
    }
    if (dp[1][200'000][0] || dp[7][200'000][0]) {
        cout << "Yes" << endl;
        return 0;
    }
    cout << "No" << endl;
    return 0;
}

回答例(Python)

準備中!