Processing math: 100%

2020年4月8日水曜日

TopCoder Single Round Match 779

 Easyを落として緑に落ちた。

 TopCoderのレートはあまり気にしていないつもりだったけど、緑に落ちたのは結構ショックだったので、もっと真剣にやらないと、と反省しました。
 それに、このEasyは通さなくてはいけない問題だったので、そこも反省。

Div1 Easy ArraySorting

 数列Aの要素をいくつか変更し、Aを広義単調増加にしたい。
 変更する要素の個数が最小になるようにし、辞書順最小のAを求める。

 まあ、LISを復元する問題といって良いと思う。
 LISに関する理解がちゃんとしていれば解けたはずなので、解けなかったのはLISの理解ができていなかったということでしょう。

 「辞書順最小」というのに惑わされるけど、「DP[i]で、長さiのLISの最終要素の最小値」を取る、という方法(たとえば、ここの説明が分かりやすいと思う)でLISを求める際に、復元用のリストを用意していれば、自然と辞書順最小のものが求められる。

 この問題も、yukicoder contest 237のNo.992 最長増加部分列の数え上げも、それほど捻った出題じゃないのに意外と難しく感じてしまうのは、LISのアルゴリズム自体がそもそも簡単じゃないからだと思う。
 とはいえ、基本的なアルゴリズムなのだから、ちゃんと身に着けておかないと……。

 以下、ACコード。
  1. import bisect
  2.  
  3. class ArraySorting():
  4. def arraySort(self, A):
  5. N=len(A)
  6. DP=[1<<31]*N
  7. fr=[-1]*N # 復元用のリスト
  8.  
  9. for i in range(N):
  10. a=A[i]
  11. pos=bisect.bisect_right(DP,a)
  12. DP[pos]=a
  13. if DP[pos-1]==1<<31:
  14. fr[i]=1
  15. else:
  16. fr[i]=DP[pos-1]
  17.  
  18. ANS=0 # LISの長さ
  19. for i in range(N):
  20. if DP[i]!=1<<31:
  21. ANS=i
  22. LASTV=DP[i]
  23.  
  24. NEXT=LASTV
  25.  
  26. B=[]
  27.  
  28. for i in range(N-1,-1,-1):
  29. a=A[i]
  30. if a==NEXT:
  31. B.append(a)
  32. NEXT=fr[i]
  33. else:
  34. B.append(NEXT)
  35.  
  36. return B[::-1]

0 件のコメント:

コメントを投稿