情報妖精の競プロ日記

AtCoderの問題に対する方針を主に書きます

AtCoder Beginner Contest 171

ABC171 解説

2020年6月21日

A: αlphabet

αが小文字であるということは、αが'a'以上'z'以下であるということです。従って、次のようなコードによって答えを求めることができます。

a = input()
if 'a' <= a and a <= 'z':
  print('a')
else:
  print('A')

また、多くの言語には標準で小文字かどうか判定する関数が用意されているので、それを使って解くこともできます。

a = input()
if str.islower(a):
  print('a')
else:
  print('A')
B: Mix Juice

N個の果物のうち、安い順にK個買うのが最適です。もしそうでない買い方をする場合、安い順に見てK+1番目以上の果物を買うことになりますが、その果物を買わずに安い方からK番目以内の果物を買うとより安くなるので、これが最適であることを示せます。
簡単な実装としては、pをソートし、先頭からK個の和を求めると良いでしょう。

N, K = map(int, input().split())
p = sorted(list(map(int, input().split())))
print(sum(p[0:K]))
C: One Quadrillion and One Dalmatians

f(x)を、整数xが与えられた時に番号xの犬の名前を返す関数とします。すると、f(x)には次のような性質があります。

  • 1 \leq x \leq 26の時、アルファベットのx番目を返す。
  • 26 < xの時、 x-126で割った値をa、あまりをbとして、 f(a) + f(b+1)を返す。

これを適切に実装すると答えを導出できます。計算量は{\rm O}(\log N)です。

def f(x):
  if 1 <= x and x <= 26:
    return chr(ord('a') + x - 1)
  else:
    return f((x - 1) // 26) + f(x % 26)
N = int(input())
print(f(N))
D: Replacing

数列D_iを、A_j=iとなるようなjの個数と定義します。この時、A_i \leq 10^5なので、Dの長さは10^5+1もあれば十分です。また、S_0を操作が行われる前の数列Aの全ての要素の和と定義します。この時、i回目の操作はD_{C_i}D_{B_i}を足し、D_{B_i}0にする操作と考えることができます。また、この時のS_i = S_{i-1} + (C_i - B_i) * (D_{B_i})と書けるので、十分に高速に求めることができます。計算量は{\rm O}(N+Q)です。

E: Red Scarf

任意の整数Aに対して、A {\rm \ xor \ } A = 0になる性質を利用します。特に、Aを奇数回{\rm \ xor \ }を取ったものはAに一致します。
b_iを番号iが書かれたすぬけくんのスカーフに書かれた整数とし、S = b_1 {\rm \ xor \ } b_2 {\rm \ xor \ } \cdots {\rm \ xor \ } b_Nとすると、a_i = b_1 {\rm \ xor \ } b_2 {\rm \ xor \ } \cdots {\rm \ xor \ } b_{i-1} {\rm \ xor \ } b_{i+1} {\rm \ xor \ } \cdots b_N = b_1 {\rm \ xor \ }  b_2 {\rm \ xor \ }  \cdots b_{i-1} {\rm \ xor \ }  b_{i+1} {\rm \ xor \ }  \cdots b_N {\rm \ xor \ } (b_i {\rm \ xor \ }  b_i) = S {\rm \ xor \ } b_iと表すことができるので、Sが求まっているならばb_i = S {\rm \ xor \ } a_iとして高速に導出できることが分かります。
ここで、a_1 {\rm \ xor \ } a_2 {\rm \ xor \ } \cdots {\rm \ xor \ } a_Nは、a_ib_iの形に展開すると各b_iを丁度奇数回ずつ含むことから、これはb_1 {\rm \ xor \ } b_2 {\rm \ xor \ } \cdots {\rm \ xor \ } b_N、すなわちSに一致するので、この問題を解くことができました。計算量は{\rm O}(N)です。

F: Strivore

まずは計算量{\rm O}(K|S|)のDPを考えてみましょう。DPを、次のように定義します。

  •  dp_{i, j}は、左からi番目までの文字を決定して、その文字列がSj番目までの文字列を部分文字列に含み、j+1番目までの文字列を部分文字列に含まないようなものの個数
  •  dp_{0, 0}1通り
  •  dp_{i, j} (j < |S|)S_jを次に使うdp_{i-1, j-1}S_{j+1}を使わないdp_{i-1, j} * 25の和
  •  dp_{i, j} (j = |S|)S_jを次に使うdp_{i-1, j-1}と自由に文字を選べるdp_{i-1, j} * 26の和
  • 答えは dp_{K + |S|, |S|}

さて、このDPでは、Sを部分文字列として含むか含まないかで遷移が変化し、文字によらないことが分かります。そこで、d_iを丁度i文字目までを見た時にSを部分文字列に含むような文字列の個数とすると、答えは\sum_{i=|S|}^{|S|+K} d_iと表せることが分かります。また、d_iSの末尾でない場所(このような場所は全部で|S|ヶ所あります)に対して全部で|S|-i個の直後のSを構成する文字に一致しない文字を挿入し、Sの末尾に文字をi-|S|個挿入するような場合の数なので、これはd_i = 25^{i-|S|} \times _{i-1}C_{i-|S|} \times 26^{K-i+|S|}として表せます。計算量は{\rm O}(K+|S|)です。