Codeforces Round 984 (Div. 3) 問題の解説

C. Anya and 1100

問題URL

Problem - C - Codeforces

解法

文字列中の特定のパターン「1100」の出現回数を管理する問題です。ある位置の文字を変更したとき、それが「1100」の存在にどのような影響を与えるかを考えます。

変更による影響は三種類あります:

  • 「1100」の個数が1増える
  • 「1100」の個数が1減る
  • 変化なし

変更箇所について、それが「1100」のどの位置(1番目〜4番目)に対応するかを列挙し、その位置から長さ4の 부분文字列を抽出して「1100」と一致するかをチェックします。一致すればその位置は「1100」に貢献しており、一致しなければ貢献していないと判断できます。

変更前後の貢献度を比較し、差分を出力します。

実装

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

bool checkContribution(int idx, const string& str) {
    const string target = "1100";
    
    // idx が最初の位置の場合
    if (idx + 3 < str.size() && str.substr(idx, 4) == target) return true;
    
    // idx が2番目の位置の場合
    if (idx - 1 >= 0 && idx + 2 < str.size() && str.substr(idx - 1, 4) == target) return true;
    
    // idx が3番目の位置の場合
    if (idx - 2 >= 0 && idx + 1 < str.size() && str.substr(idx - 2, 4) == target) return true;
    
    // idx が4番目の位置の場合
    if (idx - 3 >= 0 && str.substr(idx - 3, 4) == target) return true;
    
    return false;
}

void solve() {
    string s;
    int q;
    cin >> s >> q;
    
    const string target = "1100";
    int count = 0;
    
    // 初期状態の出現回数をカウント
    for (int i = 0; i + 3 < (int)s.size(); i++) {
        if (s.substr(i, 4) == target) count++;
    }
    
    while (q--) {
        int pos;
        char ch;
        cin >> pos >> ch;
        pos--;
        
        if (s[pos] != ch) {
            int before = checkContribution(pos, s);
            s[pos] = ch;
            int after = checkContribution(pos, s);
            
            if (before && !after) count--;
            else if (!before && after) count++;
        }
        
        cout << (count > 0 ? "YES" : "NO") << '\n';
    }
}

void setup() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
}

int main() {
    setup();
    int T;
    cin >> T;
    while (T--) solve();
    return 0;
}

D. I Love 1543

問題URL

Problem - D - Codeforces

解法

グリッドの各layer(周回路)について考えます。各layerは独立して処理できます。

各layerについて、4辺の文字を 순서대로読み取り、1つの文字列を形成します。起点はどこでも良い(环形の性质)ので、字符串の先頭3文字を末尾に追加することで闭环を模拟します。

形成された文字列において「1543」が出現する回数をカウントすれば、それがそのlayerの答えになります。全layerの合計が最終答えとなります。

実装

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int T;
    cin >> T;
    
    while (T--) {
        int n, m;
        cin >> n >> m;
        
        vector<string> grid(n + 1);
        for (int i = 1; i <= n; i++) {
            string row;
            cin >> row;
            grid[i] = " " + row;
        }
        
        const string target = "1543";
        int total = 0;
        
        int layers = min(n, m) / 2;
        for (int layer = 1; layer <= layers; layer++) {
            string layerStr;
            
            // 上辺 (左から右)
            for (int j = layer; j <= m - layer + 1; j++)
                layerStr += grid[layer][j];
            
            // 右辺 (上から下)
            for (int i = layer + 1; i <= n - layer + 1; i++)
                layerStr += grid[i][m - layer + 1];
            
            // 下辺 (右から左)
            for (int j = m - layer; j >= layer; j--)
                layerStr += grid[n - layer + 1][j];
            
            // 左辺 (下から上)
            for (int i = n - layer; i > layer; i--)
                layerStr += grid[i][layer];
            
            // 闭环处理
            layerStr += layerStr.substr(0, 3);
            
            // 出現回数をカウント
            for (int i = 0; i + 3 < (int)layerStr.size(); i++) {
                if (layerStr.substr(i, 4) == target) total++;
            }
        }
        
        cout << total << '\n';
    }
    
    return 0;
}

タグ: codeforces Algorithm string-processing competitive-programming C++

5月17日 20:24 投稿