SRM 479 250pt: TheCoffeeTimeDivOne

問題概要

0,1,...,N(N<4*10^7)の列がある。1..Nのマスには客がいて、そのうちいくつか(T<50個)のマスだけがお茶希望の客で、それ以外はコーヒー希望である。各客に希望の飲み物を出すには定数の時間がかかるし、7杯分しか入らないポットが空になったら0番まで補充しにいかなければならない。補充にも定数時間がかかる。全ての客に飲み物を渡すまでの時間を最小化する問題。

考えたこと

  • (本番はO(N)でTLEした記憶がある。定数倍の速度差に負けた)。
  • TLE厳しいので、本意ではないが真面目に早いのを書こう。
  • 基本的にはgreedy。後ろから7席置きに選んでいけばよい。
  • 補充や配るのにかかる時間は先に計算しておく。
  • お茶の配膳にかかる時間はすぐに求められる。
  • 問題はコーヒーの配膳にかかる時間だ。
  • まず、お茶の人をいないものとして考える。こうすると単なる公差7の等差数列の和なので計算できる。
  • 次に、各お茶の人について、コーヒーを配りにいくときに何回通りすぎたかを計算して足しあげる。
  • 後ろから数えた方がよかった。こういうのは混乱する。1回WAをもらった後AC。

practiceで通ったコード

計算量O(T*log T)。

#include <vector>
#include <algorithm>
using namespace std;

typedef long long int64;

struct TheCoffeeTimeDivOne {

	int64 find(int64 n, vector <int> tea) {

		sort(tea.rbegin(), tea.rend());
		int64 tee = tea.size(), coffee = n - tee;

		//給仕にかかる時間
		int64 ret = 4*n;

		//充填にかかる時間
		ret += 47 * ((tee + 6)/7);
		ret += 47 * ((coffee + 6)/7);

		//移動にかかる時間
		//tea
		for(int i=0; i<tee; i+=7){
			ret += tea[i]*2;
		}

		//coffee
		int64 time = (coffee+6)/7;
		ret += ((coffee%7 == 0 ? 7 : coffee%7) + coffee) * time;
		//追い越したのが何回か
		for(int i=0; i<tee; i++){
			ret += ((n - tea[i] - i + 6) / 7) * 2;
		}

		return ret;
	}

};