작년에는 처음 접하는거고 그냥 풀면 되는줄 알고 참가해서 liquidbird 님 도움으로 겨우 Qualification Round 만 통과했었는데

(사실 통과한것도 아니다; 이미 라지셋으로 문제풀이하신분꺼로 계속 해보고 성공하고나서 올렸으니)

올해는 제대로 한번 해보자고 벼르고 있었는데 역시나 헛짓하다가 준비는 못하고
토요일날 점심에 팀원분 결혼식갔다가, 여자친구랑 서울역사박물관가서 서울의 예전 골목길 사진도 보고,
경희궁갔다가 저녁에 집에와서 부랴부랴 풀게 되었다. 원래는 세종문화회관도 가려고 했는데 안가서 다행
세종문화회관까지 같으면 아마 구글코드잼 그냥 안풀었을지도 모르겠다 -_-a
Qualification Round 에는 총 3개의 문제가 주어지는데 각각 스몰셋과 라지셋의 데이터가 주어진다.
이 중 한문제 이상 스몰셋과 라지셋을 모두 풀어야 통과되고 Round 1 에 진출할수 있는 자격을 얻게 되어진다.
우선 처음에 시도한건 1번째 문제였으나 영어를 제대로 하지 못해 헛짓하느라 시간 다보내고 스몰셋이 실패하길래
다른사람들의 스몰셋 성공률이 높은편인 3번째 문제에 도전했다.(다행히도 통과되었다)
3번째 문제는 ThemaPark 문제로 대략적인 문제는 다음과 같다.
(원본 문제 링크 http://code.google.com/codejam/contest/dashboard?c=433101#s=p2)

롤러코스터가 있는데 같이온 사람들은 서로 같이 타려고 하는 경향이 강하다는게 문제의 발단이다.
3명이서 같이 왔으면 앞 롤러코스터에 2자리가 남아있더라도 바로 안타고 그 다음껄 탄다는거다 
그렇다고 센스있게 뒤에 1명 혹은 2명이

기다리고

기다리고 있다고 먼저 태우지는 않는다 ㅎㅎ
이런식으로 사람을 태울때 하루에 얼마나 벌수 있나? 이걸 계산하는게 문제다.(한사람당 1유로)
아 그리고 이사람들은 롤러코스터 운행 끝날때 까지 죽어라고 다시 탄다고 한다. =_= 난 한번도 못타는데;

예를 들자면 [1명, 4명, 2명, 1명] 이렇게 줄을 서서 기다린다고 하고
롤러코스터 정원은 6명이라고 하면 
1회 : 1명 + 4명
2회 : 2명 + 1명 + 1명 
3회 : 4명 + 2명
4회 : 1명 + 1명 + 4명
이런식으로 운행하게 된다. 

(+) 참고로 정원이 100명이라고 해도 1,4, 2, 1 이렇게 밖에 못탄다는거 명심!
사람은 결국 그놈이 그놈이라서 더이상 탈사람이 없으니 =_=/

문제에서 변하는 값은 

롤러코스터 정원 : k

롤러코스터 하루 운행 횟수 : R
사람들 묶음 : gi
사람들 묶음 수 : N
이제 본격적으로 문제를 풀어보자
롤러코스터 운행에 따라서 사람들은 롤러코스터 운행이 종료될때까지 반복하게 된다. 
간단하게 보자면 같이온사람의 숫자를 배열로 만들고 롤러코스터 정원이 넘지 않도록 배열의 앞부분부터 빼서 태우면 된다.
그리고 한번 탄 그룹은 배열의 마지막에 넣고 이런식으로 롤러코스터 하루 운행횟수 만큼 반복하면 된다.
이런방식으로 풀게되면 스몰셋은 간단히 통과하지만 라지셋 데이터는 제한시간 8분 안에 답이 안나온다(슈퍼컴퓨터라면 모르겠지만)
이유는 라지셋 데이터의 경우 변수 범위가 아래와 같이 엄청 크기 때문이다.
1 ≤ R ≤ 100000000
1 ≤ k ≤ 1000000000
1 ≤ N ≤ 1000
1 ≤ gi ≤ 10000000
우선 롤러코스터 정원이 장난 아니고; 롤러코스터의 하루 운행횟수도 엄청나다.
그룹이 하나뿐이어서 더하는거 없이 그냥 R 번 반복하는 반복을 돈다고 해도 시간이 많이 걸리더라
(난 솔직히 컴퓨터가 엄청 빨리 해낼줄 알았는데 실망이다.)
라지셋을 풀기 위해서 변수 범위가 제일 작은게 N, 사람들 묶음의 수인데 이걸 활용하면 된다.
예제의 그룹 움직임을 잘살펴보면
[1,4] -> [2, 1, 1] -> [4, 2] -> [1, 1, 4] -> [2, 1, 1] -> [4, 2] -> [1, 1, 4]  이런식이다.
먼가 보이지 않나? 
첫번째를 제외한 [2, 1, 1] -> [4, 2] -> [1, 1, 4] 이 부분이 계속해서 반복하게 되는것이다.
이걸 잘 이용해서 반복되는 부분을 계속해서 R 까지 반복문 도는게 아니라 그냥 곱해 버리는거다.
예제로 보자면 R=4, k=6 이고 gi=[1,4,2,1]  일때
gi 를 반복하는 녀석이 나올때까지 k 를 넘지 않도록 조합하는거다.
그러면 새로운 unique_gi = [[1,4] , [2, 1, 1] , [4, 2] , [1, 1, 4]] 이렇게 된다.
그리고 반복하는 녀석의 시작 인덱스는 1 이고 , 반복길이는 3
여기서 sum 은 python 에서 해당 배열내부의 값을 모두 더해주는 함수이다.
하루 탑승 총인원수 
= 패턴에 포함되지 않는 경우 인원수 총합 + (패턴반복수*패턴의
인원수총합

인원수총합) + 불완전 패턴의 인원수총합

= sum(패턴에 포함되지 않는 조합) + (반복하는 패턴이 완벽히 나오는 횟수 * 반복하는 패턴의 인원수 총합) + sum(unique_gi[반복시작인덱스]) + ….  + sum(unique_gi[불완전 패턴의 인덱스])
= 5 + (1 * 16) + 0

이렇게 된다. 아이고 말로 설명하려니 어렵다. python 을 모르는 경우에 대해서도 설명하려니 배열쪽이 복잡하다;
핵심은 반복되는 패턴을 찾고 그 패턴의 총합을 곱하기 하여 반복문을 없애는게 되겠습니다.
python 코드를 첨부하니 자세한 사항은 소스를 보시면 되겠습니다.

[#M_python 소스보기|소스접기|

#!/usr/bin/python
class ThemePark:
  def __init__(self):
    self.outfile = open('third_other.out','w')
    self.infile = open('C-large.in','r')
    print "start"
   
  def __del__(self):
    self.outfile.close()
    self.infile.close()
    print "end"
   
  def set_first_line_read(self, line):
    split_str = line.split(" ")
    self.day_run = int(split_str[0])
    self.people_limit = int(split_str[1])
    self.max_group_index = int(split_str[2])
   
  def set_second_line_read(self, line):
    list = line.split(” “)
    self.group_list = map(lambda x:int(x), list)
   
  def set_group_iter(self):
    people = 0
    group_index = 0
    first_group_index = 0
    tmp_list = []
    while True:
      tmp_list.append(group_index)
      people += self.group_list[group_index]
      next_group_index = self.get_next_group_index(group_index)
      if (first_group_index == next_group_index) or (people + self.group_list[next_group_index] > self.people_limit):
        if self.group_unique.count(tmp_list) != 0:
          self.unique_start_index = self.group_unique.index(tmp_list)
          self.unique_length = len(self.group_unique) – self.unique_start_index
          break
        self.group_unique.append(tmp_list)
        self.group_unique_sum.append(people)
        tmp_list = []
        people = 0
        first_group_index = next_group_index
      group_index = next_group_index
   
  def process_init(self):
    self.group_unique = []
    self.group_unique_sum = []
    self.unique_start_index = -1
    self.unique_length = -1
       
  def process(self):
    self.process_init()
    test_time = 1
    for time, line in enumerate(self.infile):
      if time == 0:
        continue
      if time%2 == 1:
        self.set_first_line_read(line.strip())
        continue
      self.set_second_line_read(line.strip())
      self.set_group_iter()
      ”"”
      print self.group_unique
      print self.group_unique_sum
      print self.unique_start_index
      print self.unique_length
      ”"”
      self.print_result(test_time, self.get_money())
      self.process_init()
      test_time += 1
         
  def get_money(self):
    if self.unique_length == 1:
      return self.day_run * sum(self.group_unique_sum)
    non_unique_list = self.group_unique_sum[:self.unique_start_index]
    money = sum(non_unique_list)
    x_times = (self.day_run – len(non_unique_list)) / self.unique_length
    money += x_times * sum(self.group_unique_sum[self.unique_start_index:self.unique_start_index+self.unique_length])
    x_mod = (self.day_run – len(non_unique_list)) % self.unique_length
    money += sum(self.group_unique_sum[self.unique_start_index:self.unique_start_index + x_mod])
    return money
   
  def get_next_group_index(self, current_group_index):
    if current_group_index + 1 >= self.max_group_index:
      return 0
    return current_group_index + 1
   
  def print_result(self, time, money):
    result_str = “Case #%(time)s: %(money)s\n” % {‘time’:time, ‘money’:money}
    self.outfile.write(result_str)
a = ThemePark()
a.process()

_M#]

혹은 구글코드잼에서 제공하는 풀이가 있으니 확인해보세요 [http://code.google.com/codejam/contest/dashboard?c=433101#s=a&a=2]