0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Atcoder解いてみた AtCoder Beginner Contest D - Adjacent Distinct String

0
Last updated at Posted at 2026-05-25

AtCoder Beginner Contest D - Adjacent Distinct String

問題はこちら

回答

各テストケースで入力される文字列の文字数を|S|とする
素直に並び替えるとかはできないので、O(|S|), O(|S| log|S|)あたりの計算量となる方法を考える
|S|の中で最も多い文字の数が、(|S|+1)/2+1を超えていたらNoを出す
Noじゃない場合、Sを構成する文字から以下の文字を選択していき、並び替え後の文字列S'を作る

貪欲に、直前に選ばれた文字とは異なる文字の中で、Sの中で最も文字数の多い文字
※一番最初は、単純にSの中で最も多い文字を選ぶ そのために、直前に選ばれた文字の初期値はあり得ない文字Aを設定する

multisetも活用することでO(|S| log|S|)で解くことができる

#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <limits.h>
#include <bitset>
#include <list>
#include <set>
#include <numeric>
#include <tuple>

int T;


int main()
{
	std::cin.tie(0);
	std::ios::sync_with_stdio(false);

	std::cin >> T;
	std::vector<std::string> ans;

	for (int t = 0; t < T; t++) {
		std::string S;

		std::cin >> S;

		std::vector<std::vector<int>> wordIdx(26);

		// 各文字のインデックスを格納
		for (int i = 0; i < S.size(); i++) {
			wordIdx[S[i] - 'a'].push_back(i);
		}

		// 降順
		std::multiset<std::pair<int, char>, std::greater<std::pair<int, char>>> ms;
		for (int i = 0; i < wordIdx.size(); i++) {
            // 0個の文字はmsにinsertしない
            if (!wordIdx[i].empty()) {
    			std::pair<int, char> p = std::make_pair(wordIdx[i].size(), i); // 各文字の数と、文字に対応する番号 (文字の数が同じな場合、文字でソート)
    			ms.insert(p);
            }
		}

		// 一番多い文字がth以上だったらアウト
		int th = (S.size() + 1) / 2 + 1;
		if (ms.begin()->first >= th) {
			ans.push_back("No");
			continue;
		}

		// 隣り合う文字が異なる文字列を生成
		// 貪欲に最も多い文字かつ、直前と異なる文字を選んでつなげる
		// 最も多い文字かつ、直前と異なる文字を取得→msから削除→答えにくっつける→最も多い文字の文字数を1減らす→msに追加
		// O(logN)
		std::string Sd;
		char select = 'A'; // 直前に選ばれる文字(最初はありない文字)
		for (int i = 0; i < S.size(); i++) {
			auto itr = ms.begin();

			// 直前に選ばれた文字と異なる文字の中で、最も文字数の多い文字を選択
			while(true) {
				// 直前に選ばれた文字と異なる文字
				if (select != itr->second + 'a') {
					// 直前に選ばれた文字の更新
					select = itr->second + 'a';
					break;
				}
				itr++;
			}

			// 直前に選ばれた文字と異なる文字の中で、最も文字数の多い文字を含むpairを取得
			std::pair<int, char> p = *itr;
			ms.erase(p);

			char word = p.second + 'a'; // 文字に戻す
			Sd += word;
			p.first--;
			ms.insert(p);
		}

		ans.push_back("Yes");
		ans.push_back(Sd);
	}

	for (std::string strAns : ans) {
		std::cout << strAns << std::endl;
	}

	return 0;
}

より、シンプルに、バグりにくいコードを書くなら以下
multiset使わない
英小文字は26種類なため、毎回26文字ループしてもOK

#include <iostream>
#include <string>
#include <map>
#include <unordered_map>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <limits.h>
#include <bitset>
#include <list>
#include <set>
#include <numeric>
#include <tuple>

int T;


int main()
{
	std::cin.tie(0);
	std::ios::sync_with_stdio(false);

	std::cin >> T;

	for (int t = 0; t < T; t++) {
		std::string S;

		std::cin >> S;

        std::vector<int> cnt(26, 0);
        for (char c : S) cnt[c - 'a']++;

        int n = S.size();
        int mx = *std::max_element(cnt.begin(), cnt.end());

        if (mx > (n + 1) / 2) {
            std::cout << "No\n";
            continue;
        }

        std::string ans;
        char prev = '#';

        for (int i = 0; i < n; i++) {
            int best = -1;

            for (int c = 0; c < 26; c++) {
                if (cnt[c] == 0) continue;
                if ('a' + c == prev) continue;

                if (best == -1 || cnt[c] > cnt[best]) {
                    best = c;
                }
            }

            ans += char('a' + best);
            prev = char('a' + best);
            cnt[best]--;
        }

        std::cout << "Yes\n";
        std::cout << ans << "\n";
	}

	return 0;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?