競プロ弱者の解答

競プロ弱者の成長記録

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

昨日はお休みして、今日はABC097でバーチャルコンテスト。
朝にバチャやってる方々もおられるようですが、出勤時間的に出られないんです。出られる方羨ましい・・
なので夜に一人でやってます。

〇コンテスト名:ABC097

〇配点:不明

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

〇今回の方針

 本番のコンテストのつもりで解く

 とにかく速く解く

コンテスト開始!

A - Colorful Transceivers

位置a,b,cに人がいる。人同士は距離d以内であれば通信できる。aとcは通信できるか?
勝手に位置関係をa,b,cの順にしてしまいたくなりますね。
テストケースが親切なので気づきますけど。
aとcがd以内、もしくはaとb,bとcがd以内ならOKですね。

a,b,c,d=map(int,input().split())
if abs(a-b)<=d and abs(c-b)<=d:
    print("Yes")
elif abs(a-c)<=d:
    print("Yes")
else:
    print("No")

2:21 AC

B - Exponential

Xが与えられ、X以下の最大のべき乗数を求めよ。
はい簡単
ループを回してiを増やしていきながら、i**2=Xならi**2を出力i**2>Xなら(i-1)**2を出力すれば、
WA
ちゃんと問題文を読みましょう。
2乗とは限らないんですね。
ただ、Xが1000以下。そして2**10=1024を知っていれば、10乗以上を考える必要がないことがわかります。
Xが1のときは考えるのが面倒なので、例外処理で1を出力してしまいます。
あとは変数ansを用意しておいて、iとjの2重ループを回す。j**iがX以下でansより大きければans=j**i。

X=int(input())
if X==1:
    print(1)
    exit()
ans=1
for i in range(2,11):
    for j in range(1001):
        if j**i<=X:
            if ans<j**i:
                ans=j**i
print(ans)

8:21 AC 1WA
なにやってんの?
あと、計算量的に余裕なのでやりませんでしたが、10**6オーダーの計算量ならj**iがXを超えた時点でbreakして枝刈りすべきでしょうね。

C - K-th Substring

sの部分文字列に関する問題で辞書順でK番目になる連続する部分文字列(同じ文字列は1つとして数える)を求めよ。
一か八か全探索。dictを用意して、初めと終わりを2重ループさせて全探索。dict内に同じ文字列が無ければ加える。
最後にdictをlistに変換してソート、listのK番目を出力!
TLE
やっぱ無理です。これで通るならB問題より簡単です。
良く見ればKが1~5ととても小さい。
これならlist Lを用意して、部分文字列の初めと終わりを2重ループさせて全探索。
面倒なのでLには空文字””を入れておく。
・部分文字列がLに含まれていないことを確認。
・Lの長さがK以下ならLに部分文字列を加えてソート
・Lの長さがK+1なら、Lの最後と部分文字列の辞書順を比較。
 ・部分文字列の方が前にくるなら、部分文字列をLに加えて、ソート。
  Lの一番後ろを切る。
 ・部分文字列の方が後にくるならループをbreakして枝刈り。
最後にLの一番後ろを出力

S=input()
K=int(input())
L=[""]
for s in range(len(S)):
    for e in range(s,len(S)):
        if S[s:e+1] in L:
            continue
        if len(L)>K:
            if S[s:e+1]>L[K]:
                break
        if S[s:e+1] not in L:
            if len(L)<=K:
                L.append(S[s:e+1])
                L.sort()
            else:
                L.append(S[s:e+1])
                L.sort()
                L=L[:K+1]
print(L[-1])

31:27AC 1TLE 2WA
14行目のソートを忘れててテストケースに1つだけ通らず2WA
結局C問題だけで3ペナ。B問題と合わせて4ペナ。

D - Equals

1からNを並べ替えた数列pがある。1~N以下の整数ペアがM個与えられ、ペアの数字は何回でも入れ替えて良い。
左からの順番と整数が一致する箇所を最大いくつにできるか?
unionfindとdictを組み合わせれば良さそうですね。
左からi番目を見ているときは、i番目と整数iの位置が同じグループか否かを判断。

N,M=map(int,input().split())
p=[0]+list(map(int,input().split()))

P=[i for i in range(N+1)]
S=[1 for i in range(N+1)]

def find(a):
    if a==P[a]:
        return a
    else:
        return find(P[a])
        
def union(b,c):
    B=find(b)
    C=find(c)
    if S[B]<S[C]:
        P[B]=P[C]
        S[C]+=S[B]
    else:
        P[C]=P[B]
        S[B]+=S[C]
        
for i in range(M):
    x,y=map(int,input().split())
    union(x,y)
D={}

for i in range(1,N+1):
    D[p[i]]=i
    
ans=0
for i in range(1,N+1):
    if find(i)==find(D[i]):
        ans+=1
print(ans)

43:52 AC
結局 43:52全完(4完)4ペナ!!!!
緊張感が足りてませんね。