あるぱかのブログ

AtCoder茶(レート578)

精進(2024/2/12)

 

AtCoder ProblemsのRecommendation(Moderate)を解く

CODE FESTIVAL 2015 あさぷろ Easy B - ヘイホー君と置き換え

diff=430くらい

リンク:B - ヘイホー君と置き換え (atcoder.jp)

概要:文字列 Sを前半後半に分けて、前半=後半にするために必要な操作数を出力してね

よくある文字列の置換操作の操作数を求める問題です。

今回は文字を自由に置き換えできるので簡単です。

 n文字目と m文字目を入れ替えみたいな制約が無い)

まず Sの文字数が奇数の場合は前半後半に分割不可能なので -1を出力します。

偶数なら最悪全文字を置き換えれば題意は満足できます。

とりあえず Sの頭から \dfrac{N}{2}文字目までを前半として文字列 A \dfrac{N}{2}文字目から最後を後半として文字列 Bとしました。

スライス記法で S[:N//2]とすることで0 ~   \dfrac{N}{2} -1文字目までを取り出しています。

あとは 0から \dfrac{N}{2}まで走査して文字が異なる場所を数え上げれば答えになります。

実際に文字列を置換する必要はありません。

 

N = int(input())
S = input()
if N % 2 != 0:
    print(-1)
else:
    A = S[:N//2]
    B = S[N//2:]
    count = 0
    for i in range(N//2):
        if A[i] != B[i]:
            count += 1
  print(count)

提出リンク:提出 #50230109 - CODE FESTIVAL 2015 あさぷろ Easy (atcoder.jp)

 

CODE FESTIVAL 2017 qual C B - Similar Arrays

diff=430くらい

リンク:B - Similar Arrays (atcoder.jp)

概要:配列 Aの各要素 A_iに対して配列 Bの各要素 B_i = A_i -1  or   A_i or  A_i +1としたときの配列 Bの全項の積が偶数になるパターン数を出力してね

配列長さ Nの制約が10以下なので最悪全探索しても 3^{10} = 59,049パターンなので間に合いそうです。

が、多重for文でややこしくなりそうなので別の方法を考えます。

今回は積が偶数か奇数かだけ分かればいいという点を使います。

かける数に1つでも偶数があれば積は偶数になります。

逆に言えばすべて奇数をかけるパターンでしか積が奇数になりません。

つまり全パターン 3^{N}から配列 Bの全要素が奇数のパターンの数を引くことで答えとなります。

またA_iが偶数なら B_i = A_i \pm1の範囲で奇数となりえるのは2通り( A_i +1, A_i -1)あり、A_iが奇数なら B_i = A_i \pm1の範囲で奇数となりえるのは1通り( A_i)あります。

配列 Aの各要素について偶奇判定を行うことで Bの全項が奇数になるパターン数を把握できます。

これにより計算量 O(N)で答えを求めることができます。

 

N = int(input())
A = list(map(int,input().split()))
count = 1
for i in A:
    if i % 2 == 0:
        count *= 2
    else:
        count *= 1
print(3**N - count)  

提出リンク:提出 #50230176 - CODE FESTIVAL 2017 qual C (atcoder.jp)

 

AtCoder Grand Contest 029 A - Irreversible operation

diff=430くらい

リンク:A - Irreversible operation (atcoder.jp)

概要: B Wからなる文字列について BWの並びを WBにする操作を可能な限りやって最大回数を出力してね

これもよくある文字列のスワップです。

この問題では文字列 Sの長さが最大 2 \times 10^{5}なので計算量 O(N)でないとTLEになります。

つまり文字列 Sを頭から走査して BWスワップをする動作を愚直に繰り返す方法では計算量が最悪 O(N^{N})となるためACできません。

(例えば B 2 \times 10^{5} -1個並んだあとに Wがあるような並び)

ということで、題意の操作を繰り返すと最終的にどういう形になるか、それに対して初期値はどのくらい離れた状態にあるのかを考えることにします。

 BWの並びを WBにするということは言い換えると Wを左側に、 Bを右側に固めることになります。

例として入力例2の BWBWBWは6回の操作で最終的に WWWBBBの並びになるはずです。

 Wの位置に着目して、最初は 1, 3, 5番目にありますが最終的には 0, 1, 2番目に移動しています。

1つ目は 1 - 0 = 1の距離を、2つ目は 3 - 1 = 2の距離を、3つ目は 5 - 2 = 3の距離を移動していることがわかります。

移動距離の総和をとると6となりこれが答えとなります。

実際には複数ある Wを区別する必要はないので、各 Wの初期位置の総和と操作完了後の Wの位置の総和を引き算することで答えを出します。

ちなみに 0 N-1の総和は \dfrac{N(N-1)}{2}で計算できます。

文字列 Sを1巡だけ走査すれば目的を果たせるので計算量は O(N)となり十分高速です。

 

S = input()
N = len(S)
count = 0
dist = 0
for i in range(N):
    if S[i] == 'W':
        count += 1
        dist += i
W = (count*(count-1))//2
print(abs(W-dist))  

提出リンク:提出 #50230261 - AtCoder Grand Contest 029