競プロ弱者の解答

競プロ弱者の成長記録

ABC093(バーチャル):水色競プロerの復習

昨日のABC156のDが解けずに爆死して一晩。やっと気力が戻ってきたので精進しました。それにしても久々にレート40以上削られました。
今日はABC093の復習です。
〇コンテスト名:ABC093

〇配点:不明

〇制限時間100分(A~Dまでの4問の時代のコンテスト)

〇今回の方針

 心のリハビリがてら気楽にいきましょう。

コンテスト開始!
A - abc of ABC
"a","b","c"からなる3文字の文字列が与えられる。並べ替えて"abc"にできるか判定せよ。

入力をリストで受け取ってソートしてリストが["a","b","c"]と一致すれば"Yes"そうでなければ"No"

S=list(input())
S.sort()
if S==["a","b","c"]:
    print("Yes")
else:
    print("No")

1:33 AC

B - Small and Large Integers
A以上B以下の整数で、A+K以下、B-K以上の数字を昇順に出力せよ。
これは地味に難しいですね。
①A+K以下でB-K以上の数字を2度数えないように注意
②A+K以下だけどBより大きい、B-K以上だけどAより小さいものに注意
ですから。
pythonなら、dictで①を回避し、②はmax,minを使って回避しました。

A,B,K=map(int,input().split())

D={}
for i in range(A,min(A+K,B)):
    D[i]=1
for i in range(max(B+1-K,A),B+1):
    D[i]=1
L=list(D)
L.sort()

for i in range(len(L)):
    print(L[i])

dictを使い、たとえば5を入れる場合、既にdictの中に5があろうがなかろうがdictの5には1を入れる。
後でdictをlistに変換し、listをソートして出力。
setを使っても良かったかもしれません。(setのほうが自然かも?)
6:32 AC

C - Same Integers
整数A,B,Cが与えられる。
①それらのうち2つに対して+1
②どれか1つに対して+2
①と②の操作を行い、A,B,Cを同じにする。
必要な最小の操作回数を求めよ。

A,B,Cの大きさの順がバラバラだと扱いにくいので、
A,B,Cはlistで受けて、ソートして大きい順に並べてしまいましょう。
これでlist[0]が最大、list[2]が最小です。
list[1]とlist[2]に対し、list[0] - list[1]だけ①を行う。
これでlist[0] == list[1] >= list[2]です。
次に、(list[0] - list[2]) % 2 == 0 であれば、list[2]に②を繰り返すだけでlist[0] == list[2]にできます。
(list[0] - list[2]) % 2 == 1であれば、list[2] == list[0] +1になるまで②を繰り返し、
最後にlist[0] とlist[1]に対して①の操作をする必要があります。

L=list(map(int,input().split()))
L.sort(reverse=True)
#print(L)
ans=0
SA=L[0]-L[1]
ans+=SA
L[2]+=SA
L[1]+=SA
#print(L)
if (L[0]-L[2])%2==0:
    ans+=(L[0]-L[2])//2
    print(ans)
else:
    ans+=(L[0]-L[2])//2+1
    ans+=1
    print(ans)

11:28 AC

D - Worst Case
高橋君は2回のコンテストに参加し、結果はA位、B位であった。
スコアをA*Bで定義したとき、高橋君よりスコアの小さい参加者は最大何人か?

これは難しい。
過去に解説を見て考え方を知ってるので何とかなりますが、初見で解いた方々の頭の中はどうなってるんでしょう?

基本的にA*B>=X*Xとなる最大のXを探します。
aを1以上の整数とすれば、
(X-a)*(X+a)はX*Xより小さいので、(X*X=X^2, (X-a)*(X+a)=X^2-a^2,です)
このaを数える方針です。
f:id:syunsuk1024:20200223111833p:plain
後で考える際に楽にするため、AとBの小さい方をA、大きい方をBとします。
・A=3,B=6とすればX=4となり、X+1とX-1を掛けたものは必ずX^2より小さくなります。
・A=3の場合は3を飛ばして2に行っても、必ずX^2より小さくなります。
・手元でテストしてOKだったので証明せずに通しましたが、
 AとBとXの関係は|X-A|<=|B-X|になるようなので、
 先に(X-a-1)*(X;a)となり、その後(X-a-1)*(X+a+1)となり
 結局X^2よりは小さくなります。
これを基本にして、例外を弾いていきましょう。

例外1.A=Bの場合
  上図ので上段も下段も3にすると、
  A*B>X*X を満たす最大のXは2ですが、X=3として、(X-a)*(X+a) a>=1としたほうが基本より1つ多くの組ができますね。
例外2.A+1=Bの場合
  上図で上段を3、下段を4にすると、
  A*B>X*X を満たす最大のXは3ですが、上段も下段も3のケースが作れません。
  なので、基本より1つ少ない組しかできません。
例外3.A*B>X*(X+1)を満たす場合
  上図で上段を3、下段を7とすると、
  A*B>X^2を満たす最大のXは4ですが、XとX+1の組でも(ここでは4と5)A*Bより小さければ、
  上段も下段もXkら始める基本より、上段X、下段X+1、上段X+1、下段Xからはじめられるこちらのほうが、
  1つ多くの組が作れます。
例外4. A!=BかつA*B=X*XとなるXが存在する場合
  上図で上段を2、下段を8とすると、
  A*B=X*Xを満たすX=4が存在します。が、問題文の条件がA*B>X*Xなので、X*Xを除く、基本より1つ少ない組が作れます。

基本にこれらの例外を加えればOKです。

Q=int(input())
for i in range(Q):
    A,B=map(int,input().split())
    if A>B:
        A,B=B,A
    if A==B:
        print((A-1)*2)
    elif A+1==B:
        print((A-1)*2)
    else:
        SQ=int(pow(A*B,0.5))
        if SQ**2==A*B:
            print((SQ-1)*2-1)
        elif SQ*(SQ+1)<A*B:
            print((SQ-1)*2+1)
        else:
            print((SQ-1)*2)

35:53 AC

もちろん初見では手も足もでません。
過去に色々な解説を見て、考え方を既に知っていたから解けた問題です。
でもいつかはこれを初見で解けるようになりたいですね。