Problem:
Data Center on Fire
今から少し未来の話である．高密度記憶および長期保存可能である記録デバイスが開発されてきたが，コンテンツが生み出される速度が異常なほどに速かったため，データセンターを設立した．データセンターを設立した当初は小さな建物だったが，増え続けるデータにあわせて何度も拡張工事をしたため，性能の異なるエレベータを何基も持つこととなった．
ところが，データセンターで火災が発生した．火は一定時間だけ経過すると上の階ないし下の階に燃え広がる．また，火がついてから一定時間だけ経過するとその階は焼失してしまう．そこでエレベータを使ってデバイスを運び出すこととした．このエレベータは耐火性能が完璧であるため，階の焼失に関わらず任意の階へ移動できる．また，非常に強力な加速減速装置を持つことから，加速および減速にかかる時間は無視できるほど小さいため，一瞬にして定常速度に加速すること，あるいは停止することができる．また，緊急時においてはいわゆる「開」ボタンが機能しないようにプログラムされているため，エレベータの停止時間は運び出す（あるいは降ろす）デバイスの個数にかかわらず一定である．また，階の焼失前に到着したエレベータによって運び出されるデバイスについては，たとえエレベータの出発前に階が焼失したとしても，焼失の影響を受けない．ただし，エレベータに乗せることができなかったデバイスは当然ながら焼失する．
エレベータはどの階から回収してよいか分からないため，デバイスのある最上階を目指すようにプログラムされている．ただし，エレベータ同士は通信可能であり，別のエレベータが目的階に到着した瞬間に情報が通信される．到着したエレベータに全てのデバイスが積みこめることがわかったときは，目的階よりも下にあり，回収可能なデバイスが残っている階のうちで最上階に目的階を変更する．また，焼失のために目的階に向かう必要性が失われたときも，同様にして目的階を変更する．目的階を変更するときに，移動方向を変更する必要があるときは，即座に移動方向を変更する．また，エレベータが満杯になってそれ以上のデバイスを積みこむことができないとき，あるいは回収可能なデバイスが残っていないときは 1 階を目指す．
あなたの仕事は，上記の条件のもとで，退避させることのできたデバイスの個数および到着時刻を求めるプログラムを作成することである．
Input
入力は複数のデータセットから構成される．それぞれのデータセットは次の形式で与えられる．
N
M
d
n
1
n
2
...
n
N
c
1
v
1
ts
1
x
1
c
2
v
2
ts
2
x
2
...
c
M
v
M
ts
M
x
M
k
tx
ty
tz
記号の意味は次のとおりである．入力中の値はすべて整数である．
N
(2 <=
N
<= 30)，
M
(1 <=
M
<= 10)はそれぞれビルの階数，エレベータの基数を表す．
d
(1000 <=
d
<= 10000)は階と階の間の距離を表す．
n
i
(0 <=
n
i
<= 100) は
i
階にあるデバイスの個数を表す．
c
i
(1 <=
c
i
<= 50)，
v
i
(1 <=
v
i
<= 2000)，
ts
i
(1 <=
ts
i
<= 20)，
x
i
(1 <=
x
i
<=
N
)はそれぞれ
i
番目のエレベータの容量，速度，停止時間，初期位置をあらわす．初期位置は何階にあるかで表される．
k
(2 <=
k
<=
N
)，
tx
(30 <=
tx
<= 300)，
ty
(30 <=
ty
<= 300)，
tz
(30 <=
tz
<= 300)はそれぞれ火元の階，火がついてから焼失するまでの時間，上に燃え移るまでの時間，下に燃え移るまでの時間を表す．
入力の終了は 2 つの 0 を含む行によってあらわされる．これはデータセットの一部ではない．
それぞれのデータセットは次の条件を満たすと仮定してよい．
単位時間の 1/1000 よりも短い時間の間に複数の階の消失が起こることはない．
単位時間の 1/1000 よりも短い時間の間に複数のエレベータが同一の階で 1 階より上にある階に到着することない．
単位時間の 1/1000 よりも短い時間の間にエレベータの到着とそのエレベータが到着しようとした階の焼失が起こることはない．
Output
それぞれのテストケースについて，回収されたデバイスの個数，および最後に回収されたデバイスが 1 階に到着してエレベータから降ろされるまでの時間を，単一の空白で区切って 1 行で出力しなさい．ただし，時間については，小数点以下に何個の数字を出力しても構わないが，0.001 を超える誤差を含めてはならない．また，1 階にあるデバイス以外は回収できなかったときは時間としてゼロを出力しなさい．
Sample Input
5 2
5000
10 20 0 30 5
10 1000 6 1
20 500 8 1
3 40 25 30
0 0
Output for the Sample Input
50 84.000

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 12


enum Type{
	arrive,
	carry_end,
	burn_start,
	burn_end,
};

struct Box{

	int capa;
	double V,stop_time;
};

struct Info{
	Info(double arg_T,int arg_ind,int arg_toward,Type arg_type){
		T = arg_T;
		ind = arg_ind;
		toward = arg_toward;
		type = arg_type;
	}
	Info(){

		T = 0;
		ind = toward = 0;
		type = arrive;
	}
	bool operator<(const struct Info& arg) const{

		return T > arg.T; //イベント発生時刻の昇順(PQ)
	}

	double T;
	int ind,toward;
	Type type;
};

int N,M;
int NUM[35],num_have[SIZE];
bool is_up[SIZE],is_stop[SIZE],is_burn_start[35];
double D;
Box box[SIZE];
double Y[SIZE],floorPOS[35];

int K;
double T_burn,T_up,T_under;
double pre_T,now_T;

priority_queue<Info> Q;
bool end_FLG = false;


//新しい目的階が決まった時に処理(Y[]の計算を前提としている)
void calcElev(int to_floor){

	double toPOS = floorPOS[to_floor];

	for(int i = 0; i < M; i++){
		if(is_stop[i])continue; //荷物の積み下ろし中

		double tmp_dist = fabs(toPOS-Y[i]);

		if(toPOS >= Y[i]){ //上にある時

			is_up[i] = true;


		}else{ //下にある時

			is_up[i] = false;
		}

		double tmp_T = now_T + tmp_dist/box[i].V;

		Q.push(Info(tmp_T,i,to_floor,arrive));
	}
}

void calcNowPos(){

	double diff = now_T-pre_T;

	for(int i = 0; i < M; i++){
		if(is_stop[i])continue;

		if(is_up[i]){

			Y[i] += box[i].V*diff;
		}else{

			Y[i] -= box[i].V*diff;
		}
	}
}


void func(){

	/* 初期化処理 */
	while(!Q.empty()){
		Q.pop();
	}

	scanf("%lf",&D);

	floorPOS[1] = 0;
	NUM[1] = 0;

	for(int i = 2; i <= N; i++){

		floorPOS[i] = D*(i-1);
	}

	int next_floor = -1;
	int sum;
	scanf("%d",&sum); //1階にある荷物は、運搬不要

	for(int i = 2; i <= N; i++){

		scanf("%d",&NUM[i]);
		if(NUM[i] > 0){

			next_floor = i;
		}
	}

	int tmp;

	for(int i = 0; i < M; i++){

		scanf("%d %lf %lf %d",&box[i].capa,&box[i].V,&box[i].stop_time,&tmp);
		Y[i] = D*(tmp-1);
	}

	scanf("%d %lf %lf %lf",&K,&T_burn,&T_up,&T_under);

	if(next_floor == -1){ //荷物なし

		printf("%d 0.000000000000\n",sum);
		return;
	}

	for(int i = 1; i <= N; i++){

		is_burn_start[i] = false;
	}

	for(int i = 0; i < M; i++){

		is_stop[i] = false;
		num_have[i] = 0;
	}
	pre_T = 0,now_T = 0;

	Q.push(Info(T_burn,K,-1,burn_end)); //K階が燃え尽きる時刻[
	is_burn_start[K] = true;

	if(K < N){

		Q.push(Info(T_up,K+1,-1,burn_start)); //K+1階が燃え始める時刻
	}
	if(K > 1){

		Q.push(Info(T_under,K-1,-1,burn_start)); //K-1階が燃え始める時刻
	}

	//各エレベーターの移動方向と、到着イベントを考える
	calcElev(next_floor);

	double last_time = 0;
	end_FLG = false;

	while(!Q.empty()){

		Info info = Q.top();
		Q.pop();

		int pre_floor = info.toward;

		if(info.type == arrive && pre_floor != 1 && pre_floor != next_floor)continue; //■■現在は無効になった命令なので読み飛ばす

		pre_T = now_T;
		now_T = info.T;

		calcNowPos(); //各エレベーターの現在位置を計算

		if(info.type == arrive){

			if(pre_floor == 1){ //積み下ろしのために1階に来た場合

				if(num_have[info.ind] > 0){

					Q.push(Info(now_T+box[info.ind].stop_time,info.ind,1,carry_end));
				}

				continue;
			}

			//荷物を積むために、ある階に到着した場合

			is_stop[info.ind] = true; //移動指示を無視する

			Q.push(Info(now_T+box[info.ind].stop_time,info.ind,pre_floor,carry_end)); //積み込み終了イベントを追加

			int can_carry = box[info.ind].capa-num_have[info.ind]; //積み込める最大数

			//その階の荷物を全て積み切れるか判断する

			if(NUM[pre_floor] <= can_carry){ //全て積み込める

				num_have[info.ind] += NUM[pre_floor];
				NUM[pre_floor] = 0;

				next_floor -= 1;

				while(next_floor > 0 && NUM[next_floor] == 0){

					next_floor--;
				}

				if(next_floor == 0){

					next_floor = 1; //■全ての荷物の運搬が完了
					end_FLG = true;
				}

				//他のエレベーターの、移動方向を変える
				calcElev(next_floor);

			}else{ //積みきれない→満杯になる

				num_have[info.ind] += can_carry;
				NUM[pre_floor] -= can_carry;
			}

		}else if(info.type == carry_end){ //積み込み終了、または積み下ろし完了

			if(pre_floor == 1){ //積み下ろしが完了した場合

				last_time = now_T; //■■注意
				sum += num_have[info.ind];
				num_have[info.ind] = 0;

				if(end_FLG)continue;

				//まだ荷物が残っている場合
				Y[info.ind] = 0;
				is_stop[info.ind] = false;

				is_up[info.ind] = true;

				double add_T = floorPOS[next_floor]/box[info.ind].V;

				Q.push(Info(now_T+add_T,info.ind,next_floor,arrive));


			}else{ //積み込みが完了した場合

				if(end_FLG == true || num_have[info.ind] == box[info.ind].capa){ //満杯の場合→荷おろしのために1階に向かう

					double add_T = floorPOS[pre_floor]/box[info.ind].V;

					Q.push(Info(now_T+add_T,info.ind,1,arrive));

				}else{ //まだ荷物がある、かつ満杯でない場合→next_floorに向かう

					Y[info.ind] = floorPOS[pre_floor];
					is_stop[info.ind] = false; //移動命令を受け付けるようにする

					is_up[info.ind] = (next_floor > pre_floor);

					double add_T = fabs(floorPOS[next_floor]-floorPOS[pre_floor])/box[info.ind].V;
					Q.push(Info(now_T+add_T,info.ind,next_floor,arrive));
				}
			}

		}else if(info.type == burn_start){ //ある階が燃え始めた場合

			Q.push(Info(now_T+T_burn,info.ind,-1,burn_end)); //焼失する時刻
			if(info.ind+1 <= N && !is_burn_start[info.ind+1]){

				Q.push(Info(now_T+T_up,info.ind+1,-1,burn_start));
				is_burn_start[info.ind+1] = true;
			}
			if(info.ind > 1 && !is_burn_start[info.ind-1]){

				Q.push(Info(now_T+T_under,info.ind-1,-1,burn_start));
				is_burn_start[info.ind-1] = true;
			}

		}else if(info.type == burn_end){ //焼失した場合

			NUM[info.ind] = 0; //運び入れられてない荷物を削除

			if(info.ind == next_floor){ //焼失した階が、現在の目的地になっている場合

				next_floor -= 1;
				while(next_floor > 0 && NUM[next_floor] == 0){

					next_floor--;
				}

				if(next_floor == 0){

					next_floor = 1; //■全ての荷物の運搬が完了
					end_FLG = true;
				}
				//他のエレベーターの、移動方向を変える
				calcElev(next_floor);
			}
		}
	}

	printf("%d %.12lf\n",sum,last_time);
}


int main(){

	while(true){
		scanf("%d %d",&N,&M);
		if(N == 0 && M == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3236
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 12


enum Type{
	arrive,
	carry_end,
	burn_start,
	burn_end,
};

struct Box{

	int capa;
	double V,stop_time;
};

struct Info{
	Info(double arg_T,int arg_ind,int arg_toward,Type arg_type){
		T = arg_T;
		ind = arg_ind;
		toward = arg_toward;
		type = arg_type;
	}
	Info(){

		T = 0;
		ind = toward = 0;
		type = arrive;
	}
	bool operator<(const struct Info& arg) const{

		return T > arg.T; //イベント発生時刻の昇順(PQ)
	}

	double T;
	int ind,toward;
	Type type;
};

int N,M;
int NUM[35],num_have[SIZE];
bool is_up[SIZE],is_stop[SIZE],is_burn_start[35],is_burn_end[35];
double D;
Box box[SIZE];
double Y[SIZE],floorPOS[35];

int K;
double T_burn,T_up,T_under;
double pre_T,now_T;

priority_queue<Info> Q;
bool end_FLG = false;

bool DEBUG = true;

//新しい目的階が決まった時に処理(Y[]の計算を前提としている)
void calcElev(int to_floor){

	double toPOS = floorPOS[to_floor];

	for(int i = 0; i < M; i++){
		if(is_stop[i])continue; //荷物の積み下ろし中

		double tmp_dist = fabs(toPOS-Y[i]);

		if(toPOS >= Y[i]){ //上にある時

			is_up[i] = true;


		}else{ //下にある時

			is_up[i] = false;
		}

		double tmp_T = now_T + tmp_dist/box[i].V;
		/*if(DEBUG){

			printf("i:%d tmp_T:%.3lf\n",i,tmp_T);
		}*/

		Q.push(Info(tmp_T,i,to_floor,arrive));
	}
}

void calcNowPos(){

	double diff = now_T-pre_T;

	for(int i = 0; i < M; i++){
		if(is_stop[i])continue;

		if(is_up[i]){

			Y[i] += box[i].V*diff;
		}else{

			Y[i] -= box[i].V*diff;
		}
	}
}


void func(){

	/* 初期化処理 */
	while(!Q.empty()){
		Q.pop();
	}

	scanf("%lf",&D);

	floorPOS[1] = 0;
	NUM[1] = 0;

	for(int i = 2; i <= N; i++){

		floorPOS[i] = D*(i-1);
	}

	int next_floor = -1;
	int sum;
	scanf("%d",&sum); //1階にある荷物は、運搬不要

	for(int i = 2; i <= N; i++){

		scanf("%d",&NUM[i]);
		if(NUM[i] > 0){

			next_floor = i;
		}
	}


	int tmp;

	for(int i = 0; i < M; i++){

		scanf("%d %lf %lf %d",&box[i].capa,&box[i].V,&box[i].stop_time,&tmp);
		Y[i] = D*(tmp-1);
		/*if(DEBUG){

			printf("Y[%d]:%.3lf\n",i,Y[i]);
		}*/
	}

	scanf("%d %lf %lf %lf",&K,&T_burn,&T_up,&T_under);

	if(next_floor == -1){ //荷物なし

			printf("%d 0.000000000000\n",sum);
			return;
		}

	for(int i = 1; i <= N; i++){

		is_burn_start[i] = false;
		is_burn_end[i] = false;
	}

	for(int i = 0; i < M; i++){

		is_stop[i] = false;
		num_have[i] = 0;
	}
	pre_T = 0,now_T = 0;

	Q.push(Info(T_burn,K,-1,burn_end)); //K階が燃え尽きる時刻[
	is_burn_start[K] = true;

	if(K < N){

		Q.push(Info(T_up,K+1,-1,burn_start)); //K+1階が燃え始める時刻
	}
	if(K > 1){

		Q.push(Info(T_under,K-1,-1,burn_start)); //K-1階が燃え始める時刻
	}

	//各エレベーターの移動方向と、到着イベントを考える
	calcElev(next_floor);

	double last_time = 0;
	end_FLG = false;

	while(!Q.empty()){

		Info info = Q.top();
		Q.pop();

		/*if(DEBUG){

			printf("\n◎◎◎ T:%.3lf next_floor:%d\n",info.T,next_floor);
			for(int i = 1; i <= N; i++){

				printf(" %d",NUM[i]);
			}
			printf("\n");

			switch(info.type){
			case arrive:
				printf("到着\n");
				break;
			case carry_end:
				printf("carry_end\n");
				break;
			case burn_start:
				printf("延焼開始\n");
				break;
			case burn_end:
				printf("焼失\n");
				break;
			}
			printf("ind:%d\n",info.ind);
		}*/

		int pre_floor = info.toward;

		if(info.type == arrive && pre_floor != 1 && pre_floor != next_floor)continue; //■■現在は無効になった命令なので読み飛ばす

		pre_T = now_T;
		now_T = info.T;


		/*if(now_T-pre_T < EPS){

			printf("BUG\n");
			return;
		}*/

		calcNowPos(); //各エレベーターの現在位置を計算



		if(info.type == arrive){

			if(pre_floor == 1){ //積み下ろしのために1階に来た場合

				if(num_have[info.ind] > 0){

					Q.push(Info(now_T+box[info.ind].stop_time,info.ind,1,carry_end));
				}

				continue;
			}

			/*if(is_burn_end[pre_floor]){

				printf("■焼失した階に到着 elev:%d pre_floor:%d next_floor:%d\n",info.ind,pre_floor,next_floor);
				if(!end_FLG){

					printf("実終了\n");
				}else{

					printf("終了\n");
				}
				return;
			}*/

			//荷物を積むために、ある階に到着した場合

			is_stop[info.ind] = true; //移動指示を無視する

			Q.push(Info(now_T+box[info.ind].stop_time,info.ind,pre_floor,carry_end)); //積み込み終了イベントを追加

			int can_carry = box[info.ind].capa-num_have[info.ind]; //積み込める最大数

			//その階の荷物を全て積み切れるか判断する

			if(NUM[pre_floor] <= can_carry){ //全て積み込める

				num_have[info.ind] += NUM[pre_floor];
				NUM[pre_floor] = 0;

				//printf("■■全て積み込めるので、next_floorを1引きます elev:%d 階:%d\n",info.ind,pre_floor);

				next_floor -= 1;

				while(next_floor > 0 && NUM[next_floor] == 0){

					next_floor--;
				}

				if(next_floor == 0){

					next_floor = 1; //■全ての荷物の運搬が完了
					end_FLG = true;
				}

				//他のエレベーターの、移動方向を変える
				calcElev(next_floor);

			}else{ //積みきれない→満杯になる

				num_have[info.ind] += can_carry;
				NUM[pre_floor] -= can_carry;
			}

		}else if(info.type == carry_end){ //積み込み終了、または積み下ろし完了

			if(pre_floor == 1){ //積み下ろしが完了した場合

				//printf("■■エレベーター%dが積み下ろしに来ました 荷物:%d next_floor:%d\n",info.ind,num_have[info.ind],next_floor);

				last_time = now_T; //■■注意
				sum += num_have[info.ind];
				num_have[info.ind] = 0;

				if(end_FLG)continue;

				//まだ荷物が残っている場合
				Y[info.ind] = 0;
				is_stop[info.ind] = false;

				is_up[info.ind] = true;

				double add_T = floorPOS[next_floor]/box[info.ind].V;

				Q.push(Info(now_T+add_T,info.ind,next_floor,arrive));


			}else{ //積み込みが完了した場合



				if(end_FLG == true || num_have[info.ind] == box[info.ind].capa){ //満杯の場合→荷おろしのために1階に向かう

					double add_T = floorPOS[pre_floor]/box[info.ind].V;

					Q.push(Info(now_T+add_T,info.ind,1,arrive));

				}else{ //まだ荷物がある、かつ満杯でない場合→next_floorに向かう

					Y[info.ind] = floorPOS[pre_floor];
					is_stop[info.ind] = false; //移動命令を受け付けるようにする

					is_up[info.ind] = (next_floor > pre_floor);

					double add_T = fabs(floorPOS[next_floor]-floorPOS[pre_floor])/box[info.ind].V;
					Q.push(Info(now_T+add_T,info.ind,next_floor,arrive));
				}
			}

		}else if(info.type == burn_start){ //ある階が燃え始めた場合

			Q.push(Info(now_T+T_burn,info.ind,-1,burn_end)); //焼失する時刻
			if(info.ind+1 <= N && !is_burn_start[info.ind+1]){

				Q.push(Info(now_T+T_up,info.ind+1,-1,burn_start));
				is_burn_start[info.ind+1] = true;
			}
			if(info.ind > 1 && !is_burn_start[info.ind-1]){

				Q.push(Info(now_T+T_under,info.ind-1,-1,burn_start));
				is_burn_start[info.ind-1] = true;
			}

		}else if(info.type == burn_end){ //焼失した場合

			NUM[info.ind] = 0; //運び入れられてない荷物を削除

			is_burn_end[info.ind] = true;

			//changeToward(info.ind); //この階に向かっているエレベーターがあれば、別のフロアに異動させる
			//printf("■■%d階が焼失 next_floor:%d\n",info.ind,next_floor);

			if(info.ind == next_floor){ //焼失した階が、現在の目的地になっている場合

				//printf("■■今、焼失階[%d]はnext_floorです\n",info.ind);

				next_floor -= 1;
				while(next_floor > 0 && NUM[next_floor] == 0){

					next_floor--;
				}

				if(next_floor == 0){

					next_floor = 1; //■全ての荷物の運搬が完了
					end_FLG = true;
				}
				//他のエレベーターの、移動方向を変える
				calcElev(next_floor);
			}
		}
	}

	printf("%d %.12lf\n",sum,last_time);
}


int main(){

	while(true){
		scanf("%d %d",&N,&M);
		if(N == 0 && M == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3152
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;

using db = double;
using ll = long long;
using vi = vector <int>;
#define op operator
#define pb push_back

const db eps = 1e-6L;
int sgn(db a, db b = 0) {
	a -= b;
	return (a > eps) - (a < -eps);
}

const int N = 33;
int n, m; db d;
int device[N];
int capacity[N], full_capacity[N];
int speed[N];
db wait_time[N], full_wait_time[N];
db pos[N];

int burn[N];

int cnt;
db timer, last_collect_time;

const db inf = 1e10L;
int goal;
db check(int i) {
	if(sgn(wait_time[i]) > 0) return wait_time[i];
	if(!capacity[i]) return (pos[i] - d) / speed[i];
	if(goal != -1) return abs(pos[i] - goal * d) / speed[i];
	if(sgn(pos[i], d) != 0) return (pos[i] - d) / speed[i];
	return inf;
}

void solve(int i, db t) {
	if(sgn(wait_time[i]) > 0)
		wait_time[i] -= t;
	else if(!capacity[i]) {
		pos[i] -= speed[i] * t;
		if(sgn(pos[i], d) == 0) {
			wait_time[i] = full_wait_time[i];
			capacity[i] = full_capacity[i];
			last_collect_time = max(last_collect_time, timer + t + wait_time[i]);
		}
	} else if(goal != -1) {
		pos[i] += sgn(goal * d - pos[i]) * speed[i] * t;
		if(sgn(pos[i], goal * d) == 0) {
			wait_time[i] = full_wait_time[i];
			int collect = min(capacity[i], device[goal]);
			//cout << capacity[i] << ' ' << device[goal] << '\n';
			capacity[i] -= collect;
			device[goal] -= collect;
			cnt += collect;
		}
	} else if(sgn(pos[i], d) != 0) {
		pos[i] -= speed[i] * t;
		if(sgn(pos[i], d) == 0 && capacity[i] != full_capacity[i]) {
			wait_time[i] = full_wait_time[i];
			capacity[i] = full_capacity[i];
			last_collect_time = max(last_collect_time, timer + t + wait_time[i]);
		}
	}
}

int main() {
	cout << fixed << setprecision(9);
	ios :: sync_with_stdio(0);

	while(cin >> n >> m && n && m) {
		cin >> d;
		for(int i = 1; i <= n; i ++)
			cin >> device[i];
		cnt = device[1]; device[1] = 0;
		timer = last_collect_time = 0;

		for(int i = 1; i <= m; i ++) {
			cin >> full_capacity[i] >> speed[i] >> full_wait_time[i] >> pos[i];
			capacity[i] = full_capacity[i];
			wait_time[i] = 0;
			pos[i] *= d;
		}

		int k, tx, ty, tz; cin >> k >> tx >> ty >> tz;
		burn[k] = tx;
		for(int i = k + 1; i <= n; i ++)
			burn[i] = (i - k) * ty + tx;
		for(int i = 1; i < k; i ++)
			burn[i] = (k - i) * tz + tx;

		for(;;) {
			//cout << "------\n";
			goal = -1;
			for(int i = 1; i <= n; i ++)
				if(device[i]) goal = i;
			db nxt = inf;
			//cout << goal << ' ' << timer << '\n';
			//for(int i = 1; i <= n; i ++) cout << device[i] << ' '; cout << '\n';
			for(int i = 1; i <= n; i ++)
				if(sgn(burn[i], timer) > 0)
					nxt = min(nxt, burn[i] - timer);
			for(int i = 1; i <= m; i ++) {
				nxt = min(nxt, check(i));
			}

			if(nxt != inf)
				for(int i = 1; i <= m; i ++)
					solve(i, nxt);
			else
				break;

			timer += nxt;
			for(int i = 1; i <= n; i ++)
				if(sgn(burn[i], timer) == 0) device[i] = 0;
		}
		cout << cnt << ' ' << last_collect_time << '\n';
	}

	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3288
final_rank: 8

code_snippet: #include<bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define EQ(a,b) (abs((a)-(b))<EPS)
#define chmin(a,b) (a) = min((a),(b))
#define chmax(a,b) (a) = max((a),(b))
using namespace std;
typedef double D;
const D EPS = 1e-8;

struct elevator{
  int cap,rem;
  D v,ts,pos,stop;
  elevator(int a,D b,D c,D d):
    cap(a),v(b),ts(c),pos(d){rem = a; stop=-1;}
  
  D reachTime(D goal){
    if(stop>-EPS)return ts - stop;
    if(rem == 0)return pos/v;
    return abs(goal - pos)/v;
  }

  int move(D goal, D t){
    if(stop>-EPS){
      stop += t;
      if(EQ(stop,ts))stop = -1;
      return 0;
    }

    if(rem==0)goal = 0;
    pos += (goal>pos)?v*t:-v*t;
    if(EQ(goal,pos)){
      stop = 0;
      if(EQ(pos,0)){
	int res = cap-rem;
	rem = cap;
	return res;
      }
    }
    return 0;
  }
};

int main(){
  int N,M;

  while(cin >> N >> M, N){
    D d;
    cin >> d;
    bool flag = false;

    vector<int> device(N);
    rep(i,N)cin >> device[i];

    vector<elevator> el;
    rep(i,M){
      int c,v,ts,x;
      cin >> c >> v >> ts >> x;
      el.push_back(elevator(c,v,ts,d*(x-1)));
    }

    D k,tx,ty,tz;
    cin >> k >> tx >> ty >> tz; k--;
    vector<D> burn(N,-1);
    burn[k] = tx;
    int uf = k+1, df = k-1;
    D nxtu = ty, nxtd = tz;

    int ans = device[0];
    D curTime = 0, lastTime = 0;
    for(;;){
      int goal = -1;
      rep(i,N)if(device[i])goal = i;
      if(goal<1)break;

      D nxtTime = 1e9;
      rep(i,N){
	if(burn[i]>-EPS)chmin(nxtTime, burn[i]);
      }
      if(uf<N)chmin(nxtTime,nxtu);
      if(df>=0)chmin(nxtTime,nxtd);

      rep(i,M)chmin(nxtTime, el[i].reachTime(d*goal) );

      curTime += nxtTime;

      rep(i,N){
	if(burn[i]>-EPS){
	  burn[i] -= nxtTime;
	  if(EQ(burn[i],0)){
	    device[i] = 0;
	    burn[i] = -1;
	  }
	}
      }

      nxtu -= nxtTime;
      if(EQ(nxtu,0)){
	if(uf<N)burn[uf] = tx;
	uf++; nxtu = ty;
      }

      nxtd -= nxtTime;
      if(EQ(nxtd,0)){
	if(df>=0)burn[df] = tx;
	df--; nxtd = tz;
      }

      rep(i,M){
	int num = el[i].move(d*goal,nxtTime);
	if(num){
	  ans += num; chmax(lastTime, curTime + el[i].ts);
	}

	if(EQ(el[i].pos,d*goal) && EQ(el[i].stop,0)){
	  int tmp = min(el[i].rem, device[goal]);
	  el[i].rem -= tmp; device[goal] -= tmp;
	  if(tmp && goal)flag = true;
	}
      }
    }

    rep(i,M){
      if(el[i].rem != el[i].cap){
	ans += el[i].cap - el[i].rem;
	D nxtTime = el[i].pos/el[i].v + el[i].ts;
	if(el[i].stop>-EPS)nxtTime += el[i].ts-el[i].stop;
        chmax(lastTime, curTime + nxtTime);
      }
    }
    cout << fixed << setprecision(6) << ans << " "
      	 << (flag?lastTime:0.0) << endl;
  }
}
accuracy: 1
time_ms: 40
memory_kb: 1308
final_rank: 4

code_snippet: #include <algorithm>
#include <numeric>
#include <queue>
#include <iostream>
#include <iomanip>
using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)

struct Event {
  double time;
  function<void ()> proc;

  Event(double time, function<void ()> proc): time(time), proc(proc) {}
  bool operator<(const Event& rhs) const { return rhs.time < time; }
};

struct Elevator {
  int capacity, speed, stopTime, target, size, rev, dir;
  double pos, time;

  Elevator(): size(0), rev(0), dir(1), time(0) {}
};

int floorCount, elevatorCount, floorDistance;
int initFireFloor, burningTime, upSpreadTime, downSpreadTime;
vector<Elevator> elevators;
vector<int> deviceCount;
vector<bool> floorBurned;
priority_queue<Event> Q;
double ansTime;
int ansCount;

void changeTarget(double time, int elevator, int stopTime);

int newTarget(int elevator, int currentTarget) {
  Elevator& e = elevators[elevator];
  if (e.size == e.capacity)
    return 0;
  for (int i = currentTarget - 1; i > 0; --i)
    if (!floorBurned[i] && deviceCount[i] > 0)
      return i;
  return 0;
}

void onReach(double time, int floor, int elevator, int rev) {
  Elevator& e = elevators[elevator];
  if (rev < e.rev) return;

  int n = min(deviceCount[floor], e.capacity - e.size);
  deviceCount[floor] -= n;
  e.size += n;
  if (floor == 0) {
    if (e.size > 0) {
      ansTime = max(ansTime, time + e.stopTime);
      ansCount += e.size;
      e.size = 0;
      e.target = floorCount;
      changeTarget(time, elevator, e.stopTime);
    }
  } else {
    if (deviceCount[floor] == 0) {
      REP(i, elevatorCount)
        if (i != elevator && elevators[i].target == floor)
          changeTarget(time, i, 0);
    }
    changeTarget(time, elevator, e.stopTime);
  }
}

void onBurned(double time, int floor) {
  floorBurned[floor] = true;
  REP(i, elevatorCount)
    if (elevators[i].target == floor)
      changeTarget(time, i, 0);
}

void changeTarget(double time, int elevator, int stopTime) {
  Elevator& e = elevators[elevator];
  int nextTarget = newTarget(elevator, e.target);
  if (e.target == nextTarget) return;
  e.target = nextTarget;
  e.pos += e.dir * (time - e.time) * e.speed;
  e.time = time + stopTime;
  double dist = e.target * floorDistance - e.pos;
  e.dir = dist >= 0 ? 1 : -1;
  e.rev += 1;
  double newTime = time + stopTime + fabs(dist) / e.speed;
  Q.push(Event(newTime, bind(onReach, newTime, e.target, elevator, e.rev)));
}

int main() {
  while (cin >> floorCount >> elevatorCount, floorCount | elevatorCount) {
    deviceCount.resize(floorCount);
    elevators.assign(elevatorCount, Elevator());
    floorBurned.assign(floorCount, false);

    cin >> floorDistance;
    REP(i, floorCount) cin >> deviceCount[i];
    REP(i, elevatorCount) {
      Elevator& e = elevators[i];
      cin >> e.capacity >> e.speed >> e.stopTime >> e.pos;
      e.pos = (e.pos - 1) * floorDistance;
      e.target = floorCount;
    }
    cin >> initFireFloor >> burningTime >> upSpreadTime >> downSpreadTime; --initFireFloor;

    ansTime = 0;
    ansCount = deviceCount[0];
    deviceCount[0] = 0;
    REP(floor, floorCount) {
      double t = floor >= initFireFloor ? upSpreadTime * (floor - initFireFloor) + burningTime
                                        : downSpreadTime * (initFireFloor - floor) + burningTime;
      Q.push(Event(t, bind(onBurned, t, floor)));
    }
    REP(i, elevatorCount) changeTarget(0, i, 0);

    for (; !Q.empty(); Q.pop()) { Q.top().proc(); }

    cout << setprecision(20);
    cout << ansCount << " " << ansTime << endl;
  }
}
accuracy: 1
time_ms: 30
memory_kb: 1348
final_rank: 3

code_snippet: #include <algorithm>
#include <queue>
#include <iostream>
#include <numeric>
#include <iomanip>
using namespace std;

#define REP(i, n) for (int i = 0; i < (n); ++i)

struct Event {
  double time;
  function<void ()> proc;

  Event(double time, function<void ()> proc): time(time), proc(proc) {}
  bool operator<(const Event& rhs) const { return rhs.time < time; }
};

int floorCount, elevatorCount, floorDistance;
int initFireFloor, burningTime, upSpreadTime, downSpreadTime;
vector<int> deviceCount;
vector<int> elevatorSize;
vector<int> elevatorCapacity;
vector<int> elevatorSpeed;
vector<int> elevatorStopTime;
vector<double> elevatorPos;
vector<double> elevatorTime;
vector<int> elevatorRev;
vector<int> elevatorTarget;
vector<int> elevatorDir;
vector<bool> floorBurned;
double ansTime;
int ansCount;

void changeTarget(priority_queue<Event>& Q, double time, int elevator, int stopTime);

int newTarget(int elevator, int currentTarget) {
  if (elevatorSize[elevator] == elevatorCapacity[elevator])
    return 0;
  for (int i = currentTarget - 1; i > 0; --i)
    if (!floorBurned[i] && deviceCount[i] > 0)
      return i;
  return 0;
}

void onReach(priority_queue<Event>& Q, double time, int floor, int elevator, int rev) {
  if (rev < elevatorRev[elevator]) return;

  int n = min(deviceCount[floor], elevatorCapacity[elevator] - elevatorSize[elevator]);
  deviceCount[floor] -= n;
  elevatorSize[elevator] += n;
  if (floor == 0) {
    if (elevatorSize[elevator] > 0) {
      ansTime = max(ansTime, time + elevatorStopTime[elevator]);
      ansCount += elevatorSize[elevator];
      elevatorSize[elevator] = 0;
      elevatorTarget[elevator] = floorCount;
      changeTarget(Q, time, elevator, elevatorStopTime[elevator]);
    }
  } else {
    if (deviceCount[floor] == 0) {
      REP(i, elevatorCount)
        if (i != elevator && elevatorTarget[i] == floor)
          changeTarget(Q, time, i, 0);
    }
    changeTarget(Q, time, elevator, elevatorStopTime[elevator]);
  }
}

void onBurned(priority_queue<Event>& Q, double time, int floor) {
  floorBurned[floor] = true;
  REP(i, elevatorCount)
    if (elevatorTarget[i] == floor)
      changeTarget(Q, time, i, 0);
}

void changeTarget(priority_queue<Event>& Q, double time, int elevator, int stopTime) {
  int nextTarget = newTarget(elevator, elevatorTarget[elevator]);
  if (elevatorTarget[elevator] == nextTarget) return;
  elevatorTarget[elevator] = nextTarget;
  elevatorPos[elevator] += elevatorDir[elevator] * (time - elevatorTime[elevator]) * elevatorSpeed[elevator];
  elevatorTime[elevator] = time + stopTime;
  double dist = elevatorTarget[elevator] * floorDistance - elevatorPos[elevator];
  elevatorDir[elevator] = dist >= 0 ? 1 : -1;
  elevatorRev[elevator] += 1;
  double newTime = time + stopTime + fabs(dist) / elevatorSpeed[elevator];
  Q.push(Event(newTime, bind(onReach, ref(Q), newTime, elevatorTarget[elevator], elevator, elevatorRev[elevator])));
}

int main() {
  while (cin >> floorCount >> elevatorCount, floorCount | elevatorCount) {
    deviceCount.resize(floorCount);
    elevatorCapacity.resize(elevatorCount);
    elevatorSpeed.resize(elevatorCount);
    elevatorStopTime.resize(elevatorCount);
    elevatorPos.resize(elevatorCount);

    cin >> floorDistance;
    REP(i, floorCount) cin >> deviceCount[i];
    REP(i, elevatorCount) cin >> elevatorCapacity[i] >> elevatorSpeed[i] >> elevatorStopTime[i] >> elevatorPos[i];
    REP(i, elevatorCount) elevatorPos[i] = (elevatorPos[i] - 1) * floorDistance;
    cin >> initFireFloor >> burningTime >> upSpreadTime >> downSpreadTime;
    --initFireFloor;

    floorBurned.assign(floorCount, false);
    elevatorSize.assign(elevatorCount, 0);
    elevatorTime.assign(elevatorCount, 0.0);
    elevatorRev.assign(elevatorCount, 0);
    elevatorDir.assign(elevatorCount, 1);
    elevatorTarget.assign(elevatorCount, floorCount);

    priority_queue<Event> Q;
    ansTime = 0;
    ansCount = deviceCount[0];
    deviceCount[0] = 0;
    REP(floor, floorCount) {
      double t = floor >= initFireFloor ? upSpreadTime * (floor - initFireFloor) + burningTime
                                        : downSpreadTime * (initFireFloor - floor) + burningTime;
      Q.push(Event(t, bind(onBurned, ref(Q), t, floor)));
    }
    REP(i, elevatorCount) changeTarget(Q, 0, i, 0);

    while (!Q.empty()) { Q.top().proc(); Q.pop(); }

    cout << setprecision(20);
    cout << ansCount << " " << ansTime << endl;
  }
}
accuracy: 1
time_ms: 30
memory_kb: 1344
final_rank: 2

code_snippet: #include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
 
const int arrive = 0;
const int burnout = 1;
const int gfloor = 2;
 
const int dy[2] = {1, -1};
 
class Elevator
{
public:
    int dev, cap, v, ts;
    double pos, stime;
 
    Elevator()
    {}
 
    Elevator(double pos, double stime, int dev, int cap, int v, int ts)
        :pos(pos),stime(stime),dev(dev),cap(cap),v(v),ts(ts)
    {}
};
 
class Event
{
public:
    int type, bpos;
    double time;
 
    Elevator e;
 
    Event(int type, int bpos, double time)
        :type(type), bpos(bpos), time(time)
    {}
 
    Event(int type, int bpos, double time, Elevator e)
        :type(type),bpos(bpos),time(time),e(e)
    {}
 
    bool operator<(const Event& e) const
    {
        return time > e.time;
    }
};
 
int N,M,K,T[3],devices[33];
bool burn[33];
double D[33];
 
bool limit(Elevator& e)
{
    return e.cap == e.dev;
}
 
double arvTime(int dst, Elevator& e, double t)
{
    double res = (max(e.pos, D[dst]) - min(e.pos, D[dst])) / e.v;
 
    return t + res;
}
 
Elevator arrived(Event& e)
{
    int n = min(devices[e.bpos], e.e.cap - e.e.dev);
    devices[e.bpos] -= n;
 
    Elevator res = Elevator(D[e.bpos], e.time + e.e.ts, e.e.dev+n, e.e.cap, e.e.v, e.e.ts);
    return res;
}
 
Event changeObj(Elevator& e, int d, double t)
{
    double curpos = e.pos;
    double movet = max(e.stime, t);
 
    if(D[d] > e.pos) curpos += e.v * (movet-e.stime);
    else             curpos -= e.v * (movet-e.stime);
 
    bool back = true;
 
    int dst = 1;
    for(int i = N; i >= 2; i--) {
        if(!burn[i] && devices[i] != 0) {
            dst = i;
            back = false;
            break;
        }
    }
 
    int type = arrive;
    if(limit(e) || back) {
        dst = 1;
        type = gfloor;
    }
 
    e.pos = curpos;
    double arv = arvTime(dst, e, movet);
 
    Elevator ne = Elevator(curpos, movet, e.dev, e.cap, e.v, e.ts);
    Event res = Event(type, dst, arv, ne);
 
    return res;
}
 
 
void finished(int p, double t, priority_queue<Event>& q)
{
    priority_queue<Event> nq;
    while(!q.empty()) {
        Event e = q.top(); q.pop();
         
        if(e.type == arrive) {
            if(e.bpos == p) {
                Event ne = changeObj(e.e, e.bpos, t);
                nq.push(ne);
            }
            else {
                nq.push(e);
            }
             
        }
        else
        {
            nq.push(e);
        }
    }
 
    q = nq;
}
 
void burned(int p, double t, priority_queue<Event>& q)
{
    if(burn[p]) return;
    burn[p] = true;
 
    priority_queue<Event> nq;
    while(!q.empty()) {
        Event e = q.top(); q.pop();
         
        if(e.type == arrive) {
            if(e.bpos == p) {
                Event ne = changeObj(e.e, e.bpos, t);
                nq.push(ne);
            }
 
            else {
                nq.push(e);
            }
             
        }
        if(e.type == burnout) {
            if(e.bpos != p)
                nq.push(e);
        }
        if(e.type == gfloor) {
            nq.push(e);
        }
    }
 
    q = nq;
}
 
 
 
void simulate(priority_queue<Event>& q)
{
    int cnt=devices[1];
    double last=0;
 
    while(!q.empty()) {
        Event e = q.top(); q.pop();
        if(e.type == arrive) {
            double nt = e.time + e.e.ts;
            Elevator arv = arrived(e);
            q.push(changeObj(arv, e.bpos, nt));
 
            if(devices[e.bpos] == 0)
                finished(e.bpos, e.time, q);
        }
        if(e.type == burnout) {
            burned(e.bpos, e.time, q);
        }
        if(e.type == gfloor) {
            if(e.e.dev != 0) {
                double nt = e.time + e.e.ts;
                cnt += e.e.dev;
                e.e.dev = 0;
                e.e.pos = D[1];
                e.e.stime = nt;
                last = max(last, e.e.stime);
 
                q.push(changeObj(e.e, e.bpos, nt));
            }
        }
    }
 
    if(cnt==devices[1]) last = 0;
    printf("%d %.3lf\n", cnt, last);
}
 
int main()
{
    while(cin >> N >> M, (N||M)) {
        memset(burn, 0, sizeof(burn));
 
        int dd;
        cin >> dd;
        D[1] = 0;
        for(int i = 1; i < N; i++)
            D[i+1] = D[i] + dd;
 
        for(int i = 1; i <= N; i++)
            cin >> devices[i];
 
        priority_queue<Event> q;
        for(int i = 0; i < M; i++) {
            int c,v,ts,x;
            cin >> c >> v >> ts >> x;
            Elevator e = Elevator(D[x], 0, 0, c, v, ts);
            q.push(changeObj(e, 1, 0));
        }
 
 
        cin >> K >> T[0] >> T[1] >> T[2];
 
        int S = 0;
        for(int i=K; i<=N; i++) {
            q.push(Event(burnout, i, S+T[0]));
            S += T[1];
        }
 
        S = 0;
        for(int i=K; i>=2; i--) {
            q.push(Event(burnout, i, S+T[0]));
            S += T[2];
        }
 
        simulate(q);

    }
}
accuracy: 1
time_ms: 170
memory_kb: 972
final_rank: 7

code_snippet: #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

enum EventKind {
  Fire,
  ElevetorEnd
};

struct Event {
  EventKind kind;
  double t;
  int floor;
  int index;
  Event() {;}
  Event(EventKind kind, double t, int floor, int index)
    : kind(kind), t(t), floor(floor), index(index) {;}
  bool operator<(const Event &rhs) const {
    if (t != rhs.t) { return t > rhs.t; }
    return floor < rhs.floor;;
  }
};

int n, m, k, tfloor, tup, tlower;
double d;
int device[50];
int capacity[50];
double v[50];
int tstop[50];
double elevetorFrom[50];
double elevetorStart[50];
double elevetorWait[50];
int elevetorDir[50];
int elevetorTo[50];
int elevetorRide[50];

void dfsFire(priority_queue<Event> &que, int floor, int parent, int t) {
  if (floor <= -1 || floor >= n) { return; }
  que.push(Event(Fire, t + tfloor, floor, 0));
  int nfloor = floor + 1;
  if (nfloor != parent) {
    dfsFire(que, nfloor, floor, t + tup);
  }
  nfloor = floor - 1;
  if (nfloor != parent) {
    dfsFire(que, nfloor, floor, t + tlower);
  }
}

void SetElevetor(priority_queue<Event> &que, int index, double t) {
  double pos = elevetorFrom[index] + v[index] * elevetorDir[index] * max(0.0, (t - elevetorStart[index] - elevetorWait[index]));
  assert(pos >= -EPS);
  elevetorFrom[index] = pos;
  elevetorWait[index] = max(0.0, elevetorWait[index] + elevetorStart[index] - t);
  elevetorStart[index] = t;
  if (elevetorRide[index] != capacity[index]) {
    for (int y = n - 1; y >= 0; y--) {
      if (device[y] == 0) { continue; }
      if (elevetorTo[index] == y) { return; }
      //cout << index << " " << elevetorTo[index] << " " << y << endl;
      elevetorDir[index] = y * d > pos ? 1 : -1;
      elevetorTo[index] = y;
      double nt = fabs(pos - elevetorTo[index] * d) / v[index] + t + elevetorWait[index];;
      //cout << index << " " << nt << " " << y << endl;
      que.push(Event(ElevetorEnd, nt, elevetorTo[index], index));
      return;
    }
  }
  if (elevetorTo[index] == 0) {
    elevetorDir[index] = 0;
    return;
  }
  elevetorDir[index] = -1;
  elevetorTo[index] = 0;
  double nt = fabs(pos - elevetorTo[index] * d) / v[index] + t + elevetorWait[index];
  //cout << index << " " << nt << " " << 0 << endl;
  que.push(Event(ElevetorEnd, nt, elevetorTo[index], index));
  return;
}

int main() {
  while (scanf("%d %d", &n, &m),n|m) {
    int ans = 0;
    double anst = 0.0;
    priority_queue<Event> que;
    scanf("%lf", &d);
    REP(i, n) { scanf("%d", &device[i]); }
    ans += device[0];
    device[0] = 0;
    REP(i, m) {
      int y;
      scanf("%d %lf %d %d", &capacity[i], &v[i], &tstop[i], &y);
      y--;
      elevetorFrom[i] = y * d;
      elevetorStart[i] = 0;
      elevetorWait[i] = 0;
      elevetorDir[i] = 1;
      elevetorTo[i] = -1;
      elevetorRide[i] = 0;
      SetElevetor(que, i, 0);
    }
    scanf("%d %d %d %d", &k, &tfloor, &tup, &tlower);
    k--;
    dfsFire(que, k, k, 0);
    while (!que.empty()) {
      Event event = que.top();
      que.pop();
      if (event.kind == ElevetorEnd && event.floor != elevetorTo[event.index]) {
        continue;
      }
      //cout << event.kind << " " << event.t << " " << event.floor << " " << event.index << endl;
      if (event.kind == Fire) {
        //cout << event.t << endl;
        device[event.floor] = 0;
      } else if (event.kind == ElevetorEnd) {
        if (event.floor == 0) {
          ans += elevetorRide[event.index];
          if (elevetorRide[event.index] != 0) {
            anst = max(anst, event.t + tstop[event.index]);
          }
          elevetorFrom[event.index] = event.floor * d;
          elevetorStart[event.index] = event.t;
          elevetorRide[event.index] = 0;
          elevetorWait[event.index] = tstop[event.index];
        } else {
          //cout << event.kind << " " << event.t << " " << event.floor << " " << event.index << endl;
          int ride = min(capacity[event.index] - elevetorRide[event.index], device[event.floor]);
          device[event.floor] -= ride;
          elevetorFrom[event.index] = event.floor * d;
          elevetorStart[event.index] = event.t;
          elevetorRide[event.index] += ride;
          elevetorWait[event.index] = tstop[event.index];
        }
      } else {
        assert(false);
      }
      REP(i, m) { SetElevetor(que, i, event.t); }
    }
    printf("%d %.3lf\n", ans, anst);
  }
}
accuracy: 1
time_ms: 30
memory_kb: 972
final_rank: 1