0w1

GCJ 2017 Qual C. Bathroom Stalls ( Math )

Dashboard - Qualification Round 2017 - Google Code Jam

題意:
有 N 個空間排成一排,有 K 個人依序決定自己要進哪個空間。令一個空間 i 的左邊連續空房間的數量為 L[ i ],右邊連續空房間的數量為 R[ i ],那麼任何人都會優先考慮 min( L[ i ], R[ i ] ) 最大的房間,若有多個,便考慮 max( L[ i ], R[ i ] ) 最大的房間,若還是有多個,會選擇 i 最小的房間佔據。問第 K 個人選擇的房間的 R, L 值分別是多少。

制約:
1 ≤ T ≤ 100.
1 ≤ K ≤ N.
1 ≤ N ≤ 1e18.

解法:
這種問題很常見,首先這個問題可以捨去關於下標的資訊,只用空區間長度和對應的數量描述。直覺上可以知道出現的長度種類不會超過 2 * lg N。如果用二元樹擴展的樣子去看,可以發現每層出現的值種類不會超過兩種。因此考慮一層一層擴展,每一層至多兩個元素。

時間 / 空間複雜度:
O( lg N )

from collections import defaultdict
from queue import Queue

T = int( input() )
for ti in range( 1, T + 1, 1 ):
  N, K = map( int, input().split() )
  ans_l, ans_r = -1, -1
  que = Queue()
  que.put( [ N, 1 ] );
  while K > 0:
    cnt = defaultdict( int )
    while K > 0 and not que.empty():
      n, c = que.get()
      K -= c
      ans_l, ans_r = n >> 1, n - 1 >> 1
      cnt[ ans_l ] += c
      cnt[ ans_r ] += c
    for v in sorted( cnt.keys(), reverse = True ):
      if v == 0:
        break
      else:
        que.put( [ v, cnt[ v ] ] )
  print( "Case #%d: %d %d" % ( ti, ans_l, ans_r ) )