公式

C - 1122 String 解説 by mechanicalpenciI


与えられた文字列が 1122 文字列の \(3\) つの条件をみたしているかそれぞれ確認すれば良いです。
\(3\) つめの条件は、\(1,2\) つめの条件がみたされている仮定のもとで、以下の \(2\) 通りなどのようにも言い換えられるため、直接確認する代わりにそのことを確認しても良いです。 なお、\(S_i\)\(S\)\(i\) 文字目を表すものとします。

  • \(S_1,S_3,\ldots, S_{|S|-1}\) はすべて異なる。
  • \(S\) の各文字 \(S_i\) について、\(S\) の中にその文字と一致するものはちょうど \(2\) つ存在する。
    すなわち、\(1\) 以上 \(|S|\) 以下の任意の整数 \(i\) について、\(S_i=S_j\) となる \(j\) \((1\leq j\leq |S|)\) はちょうど \(2\) つ存在する。

計算量は元の方法では \(O(\lvert S\rvert+C)\) です。ここで、 \(C\)\(S\) に使われる候補となる文字の種類数であり、今回の問題では \(C=26\) となります。言い換えた後の条件の確認には、ナイーブに実装したとき \(\Theta(\lvert S\rvert^2)\) の計算量がかかりますが、今回は \(\lvert S\rvert\leq 100\) のため時間的に問題ありません。よって、いずれの方法でも十分高速に判定を行うことができ、この問題を解くことができました。

c++ による実装例:

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

int main() {
	int n;
	string s;
	int cnt[26]={};
	bool flag=true;

	cin>>s;
	n=s.size();
	if(n%2==1)flag=false;
	if(flag){
		for(int i=0;i<(n/2);i++){
			if(s[2*i]!=s[2*i+1])flag=false;
		}
	}
	if(flag){
		for(int i=0;i<n;i++){
			cnt[s[i]-'a']++;
		}
		for(int i=0;i<26;i++){
			if((cnt[i]!=0)&&(cnt[i]!=2))flag=false;
		}
	}

	if(flag)cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
	return 0;
}

Python による実装例:

s=input()
flag=True

if len(s)%2==1:
    flag=False

if flag:
    for i in range(len(s)//2):
        if s[2*i]!=s[2*i+1]:
            flag=False

cnt=[0 for i in range(26)]
if flag:
    for i in range(len(s)):
        cnt[ord(s[i])-ord('a')]+=1
    for i in range(26):
        if cnt[i]!=0 and cnt[i]!=2:
            flag=False

if flag:
    print("Yes")
else:
    print("No")

投稿日時:
最終更新: