Problem:
Problem H:
Ramen Shop
Ron is a master of a ramen shop.
Recently, he has noticed some customers wait for a long time. This has been caused by lack of
seats during lunch time. Customers loses their satisfaction if they waits for a long time, and
even some of them will give up waiting and go away. For this reason, he has decided to increase
seats in his shop. To determine how many seats are appropriate, he has asked you, an excellent
programmer, to write a simulator of customer behavior.
Customers come to his shop in groups, each of which is associated with the following four
parameters:
T
i
: when the group comes to the shop
P
i
: number of customers
W
i
: how long the group can wait for their seats
E
i
: how long the group takes for eating
The
i
-th group comes to the shop with
P
i
customers together at the time
T
i
. If
P
i
successive
seats are available at that time, the group takes their seats immediately. Otherwise, they waits
for such seats being available. When the group fails to take their seats within the time
W
i
(inclusive) from their coming and strictly before the closing time, they give up waiting and go
away. In addition, if there are other groups waiting, the new group cannot take their seats until
the earlier groups are taking seats or going away.
The shop has
N
counters numbered uniquely from 1 to
N
. The
i
-th counter has
C
i
seats. The
group prefers “seats with a greater distance to the nearest group.” Precisely, the group takes
their seats according to the criteria listed below. Here,
S
L
denotes the number of successive
empty seats on the left side of the group after their seating, and
S
R
the number on the right
side.
S
L
and
S
R
are considered to be infinity if there are no other customers on the left side
and on the right side respectively.
Prefers seats maximizing min{
S
L
,
S
R
}.
If there are multiple alternatives meeting the first criterion, prefers seats maximizing
   max{
S
L
,
S
R
}.
If there are still multiple alternatives, prefers the counter of the smallest number.
If there are still multiple alternatives, prefers the leftmost seats.
When multiple groups are leaving the shop at the same time and some other group is waiting
for available seats, seat assignment for the waiting group should be made after all the finished
groups leave the shop.
Your task is to calculate the average satisfaction over customers. The satisfaction of a customer
in the
i
-th group is given as follows:
If the group goes away without eating, -1.
Otherwise, (
W
i
-
t
i
)/
W
i
where
t
i
is the actual waiting time for the
i
-th group (the value ranges between 0 to 1 inclusive).
Input
The input consists of multiple datasets.
Each dataset has the following format:
N M T
C
1
C
2
...
C
N
T
1
P
1
W
1
E
1
T
2
P
2
W
2
E
2
...
T
M
P
M
W
M
E
M
N
indicates the number of counters,
M
indicates the number of groups and
T
indicates the
closing time. The shop always opens at the time 0. All input values are integers.
You can assume that 1 ≤
N
≤ 100, 1 ≤
M
≤ 10
...(truncated)

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 105
#define SIZE2 10005

enum Type{
	type_END,
	type_ATE,
	type_WAIT_OUT,
	type_IN,
};

struct Info{

	int T,P,W,E;
};

struct Event{
	Event(int arg_T,int arg_ind,Type arg_type){
		T = arg_T;
		ind = arg_ind;
		type = arg_type;
	}
	Event(){

		T = ind = 0;
		type = type_IN;
	}
	bool operator<(const struct Event &arg) const{
		if(T != arg.T){

			return T > arg.T; //時刻の昇順(PQ)
		}else{

			return type > arg.type; //退出を先に処理(PQ)
		}
	}

	int T,ind;
	Type type;
};

struct DATA{
	void set(int arg_ind,int arg_SL,int arg_SR){
		ind = arg_ind;
		SL = arg_SL;
		SR = arg_SR;
	}

	int ind,SL,SR;
};

struct LOC{
	void set(int arg_c_ind,int arg_left){
		c_ind = arg_c_ind;
		left = arg_left;
	}

	int c_ind,left;
};

int N,M,LAST;
int C[SIZE]; //各カウンターに何席あるか
map<int,int> REV; //来店時刻からグループ番を引く
map<int,bool> MAP;
bool table[SIZE][SIZE],after_wait[SIZE2];
int nearL[SIZE][SIZE],nearR[SIZE][SIZE];
int C_IND[SIZE2],LEFT[SIZE2];
Info info[SIZE2];

//カウンター[c_ind]で、グループ[ind]が座る位置を探す(なければ-1)を返却
DATA searchPos(int c_ind,int ind){ //100

	DATA ret;
	ret.set(BIG_NUM,-1,-1);

	int min_maxi= -BIG_NUM,max_maxi = -BIG_NUM;
	int len = info[ind].P;

	for(int i = 1; i+len-1 <= C[c_ind]; i++){ //左端候補を走査

		if((nearR[c_ind][i] <= i+len-1))continue;

		int SL = min(BIG_NUM,(i-nearL[c_ind][i])-1);
		int SR = min(BIG_NUM,(nearR[c_ind][i+len-1]-(i+len-1)-1));

		if(min(SL,SR) < min_maxi)continue;

		if(min(SL,SR) > min_maxi){ //最小値の最大値更新

			min_maxi = min(SL,SR);
			max_maxi = max(SL,SR);
			ret.set(i,SL,SR);

		}else if(min(SL,SR) == min_maxi){ //最小値の最大値が同点

			if(max(SL,SR) > max_maxi){ //最大値更新

				max_maxi = max(SL,SR);
				ret.set(i,SL,SR);

			}
		}
	}

	return ret;
}

void updateDATA(int ind,bool is_in){ //カウンターの状態の更新

	int c_ind = C_IND[ind];
	int left = LEFT[ind];
	int len = info[ind].P;

	for(int i = left; i <= left+len-1; i++){

		if(is_in){ //新しく座る

			table[c_ind][i] = true;

		}else{ //席を立つ

			table[c_ind][i] = false;
		}
	}

	//nearLの再計算
	int last = -(BIG_NUM+SIZE);
	for(int i = 1; i <= C[c_ind]; i++){

		if(table[c_ind][i]){

			last = i;
			nearL[c_ind][i] = i;
		}else{

			nearL[c_ind][i] = last;
		}
	}

	//nearRの再計算
	last = BIG_NUM+SIZE;
	for(int i = C[c_ind]; i >= 1; i--){

		if(table[c_ind][i]){

			last = i;
			nearR[c_ind][i] = i;
		}else{

			nearR[c_ind][i] = last;
		}
	}
}

LOC searchLOC(int ind){ //座れるカウンターと、その位置を調べる

	LOC ret;

	ret.set(-1,-1);

	int min_maxi = -BIG_NUM,max_maxi = -BIG_NUM;


	for(int i = 0; i < N; i++){ //N個のカウンターすべてを見る

		DATA tmpD = searchPos(i,ind);
		if(tmpD.ind == BIG_NUM)continue; //座れる場所なし

		if(min_maxi < min(tmpD.SL,tmpD.SR)){ //最小値の最大値更新
			min_maxi = min(tmpD.SL,tmpD.SR);
			max_maxi = max(tmpD.SL,tmpD.SR);
			ret.set(i,tmpD.ind);

		}else if(min_maxi == min(tmpD.SL,tmpD.SR)){ //最小値の最大値が同点

			if(max_maxi < max(tmpD.SL,tmpD.SR)){ //最大値の最大値更新

				max_maxi = max(tmpD.SL,tmpD.SR);
				ret.set(i,tmpD.ind);
			}
		}
	}

	return ret;
}

void func(){

	MAP.clear();
	REV.clear();

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

		scanf("%d",&C[i]);
	}

	priority_queue<Event> Q;

	int div = 0;

	for(int i = 0; i < M; i++){//グループの情報を取得

		scanf("%d %d %d %d",&info[i].T,&info[i].P,&info[i].W,&info[i].E);

		REV[info[i].T] = i; //来店時刻による逆引き表
		div += info[i].P;

		Q.push(Event(info[i].T,i,type_IN));
	}

	Q.push(Event(LAST,-1,type_END)); //閉店

	//カウンターの情報の初期化
	for(int i = 0; i < N; i++){
		for(int k = 1; k <= C[i]; k++){

			table[i][k] = false;
			nearL[i][k] = -(BIG_NUM+SIZE); //kおよびkより左で、最も近い、誰かが座っている椅子の番号
			nearR[i][k] = BIG_NUM+SIZE; //kおよびkより右で、最も近い、誰かが座っている椅子の番号
		}
	}

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

		after_wait[i] = false;
		C_IND[i] = -1;
	}


	int now = 0;
	double ans = 0;

	while(!Q.empty()){
		Event event = Q.top();
		Q.pop();

		now = event.T;

		if(now == LAST)break;

		if(event.type == type_IN){ //来店

			if(MAP.size() > 0){ //待ち行列あり

				MAP[info[event.ind].T] = true; //待ち行列に加える
				Q.push(Event(now+info[event.ind].W,event.ind,type_WAIT_OUT)); //食べずに退店イベントの追加

				continue;
			}

			//MAP.size() == 0

			LOC loc = searchLOC(event.ind); //座れるカウンターと、その位置を調べる

			if(loc.c_ind == -1){ //現在座れる椅子がなかった場合

				MAP[info[event.ind].T] = true; //待ち行列に加える
				Q.push(Event(now+info[event.ind].W,event.ind,type_WAIT_OUT)); //食べずに退店イベントの追加

			}else{ //現在座れる椅子があった場合

				ans += 1.0*info[event.ind].P; //待ち時間0

				C_IND[event.ind] = loc.c_ind;
				LEFT[event.ind] = loc.left;

				updateDATA(event.ind,true);

				Q.push(Event(now+info[event.ind].E,event.ind,type_ATE)); //食べ終わって退店イベントの追加
			}

		}else{ //type_ATE または type_WAIT_OUT

			bool FLG = true; //待ち行列を消化して良いか

			set<int> SET;

			if(event.type == type_ATE){ //食べ終わり

				//■同時刻に退店するグループを、全て出す(食べて退店)→待ち行列にはいないはず
				while(true){

					//退店処理
					updateDATA(event.ind,false);

					if(Q.empty() || Q.top().T != now || Q.top().type != type_ATE)break;

					event = Q.top();
					Q.pop();
				}

			}else if(event.type == type_WAIT_OUT){

				//■同時刻に退店するグループを、全て出す(食べずに退店)

				while(true){

					if(!after_wait[event.ind]){ //待っている途中で席に座らなかった場合

						SET.insert(event.ind); //待ち行列にいるはず
					}

					if(Q.empty() || Q.top().T != now || Q.top().type != type_WAIT_OUT)break;

					event = Q.top();
					Q.pop();
				}

				if(SET.size() == 0)continue; //有効な情報なし

				if(MAP.size() > 0){

					int work_ind = REV[MAP.begin()->first]; //待ち集団の先頭

					if(SET.count(work_ind) > 0){ //待ち集団の先頭の退出時刻が到来した場合

						//■■まずは先頭を消す
						ans -= 1.0*info[work_ind].P;

						MAP.erase(info[work_ind].T);

						SET.erase(work_ind);

					}else{ //待ち行列の先頭が、引き続き待つ場合

						FLG = false; //待ち行列は消化しない

						for(int g: SET){

							ans -= 1.0*info[g].P;
							MAP.erase(info[g].T);
						}
						SET.clear();
					}
				}
			}

			if(!FLG)continue;

			//FLG == true;

			//新たに座れるようになった人々を座らせる
			while(true){

				if(MAP.size() == 0)break;

				auto at = MAP.begin();
				int tmp_ind = REV[at->first]; //待ち行列の先頭グループ

				LOC loc = searchLOC(tmp_ind);

				if(loc.c_ind == -1){
					if(now == info[tmp_ind].T+info[tmp_ind].W){

						MAP.erase(info[tmp_ind].T);

						continue;
					}else{

						break; //まだ座れない
					}
				}

				after_wait[tmp_ind] = true;

				double bunshi = info[tmp_ind].W - (now-info[tmp_ind].T);
				double bunbo = info[tmp_ind].W;

				ans += (bunshi/bunbo)*info[tmp_ind].P;

				C_IND[tmp_ind] = loc.c_ind;
				LEFT[tmp_ind] = loc.left;
				updateDATA(tmp_ind,true);

				Q.push(Event(now+info[tmp_ind].E,tmp_ind,type_ATE));

				SET.erase(tmp_ind);
				MAP.erase(info[tmp_ind].T);
			}

			//■■席に座れなかった、退出予定時刻到来者を待ち行列から消す
			for(int g: SET){

				ans -= 1.0*info[g].P;
				MAP.erase(info[g].T);
			}
		}
	}

	for(auto at = MAP.begin(); at != MAP.end(); at++){

		int tmp_ind = REV[at->first];
		ans -= 1.0*info[tmp_ind].P;
	}

	printf("%.16lf\n",ans/div);
}

int main(){


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

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 4808
final_rank: 3

code_snippet: #include <cstdio>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <climits>
#include <cfloat>
using namespace std;

class Data
{
public:
    long long time;
    int id;
    int kind; // 0 : 客の来店
              // 1 : 待ち時間が長く帰宅
              // 2 : 食事を終えて帰宅
              // 3 : 閉店
    Data(long long time0, int id0, int kind0){
        time = time0;
        id = id0;
        kind = kind0;
    }
    bool operator< (const Data& d) const{
        return make_pair(time, kind) < make_pair(d.time, d.kind);
    }
};

pair<int, int> findCounter(const vector<vector<bool> >& used, int num)
{
    int n = used.size();

    int sl = -1;
    int sr = -1;
    pair<int, int> ret(-1, -1);
    for(int i=0; i<n; ++i){
        int m = used[i].size();
        int size = 0;
        for(int j=0; j<m; ++j){
            if(used[i][j]){
                size = 0;
                continue;
            }

            ++ size;
            if(size >= num){
                int sl2;
                int sr2;
                int k;
                if(j+1 == size && j == m-1){
                    sl2 = sr2 = INT_MAX;
                    k = 0;
                }else if(j+1 == size){
                    sl2 = INT_MAX;
                    sr2 = size - num;
                    k = 0;
                }else if(j == m-1){
                    sl2 = size - num;
                    sr2 = INT_MAX;
                    k = j - num + 1;
                }else{
                    sl2 = (size - num) / 2;
                    sr2 = (size - num + 1) / 2;
                    k = j - size + (size - num) / 2 + 1;
                }
                if(min(sl2, sr2) > min(sl, sr) || (min(sl2, sr2) == min(sl, sr) && max(sl2, sr2) > max(sl, sr))){
                    sl = sl2;
                    sr = sr2;
                    ret = make_pair(i, k);
                }
            }
        }
    }

    return ret;
}

int main()
{
    for(;;){
        int n, m, closeTime; // カウンター数、グループ数、閉店時間
        cin >> n >> m >> closeTime;
        if(n == 0)
            return 0;

        vector<int> counter(n); // 各カウンターの席の数
        for(int i=0; i<n; ++i)
            cin >> counter[i];
        vector<vector<bool> > used(n); // 使用中のカウンターの席
        for(int i=0; i<n; ++i)
            used[i].assign(counter[i], false);

        vector<int> come(m), num(m), wait(m), eat(m); // 来店時間、各グループの客の人数、最大待ち時間、食事時間
        for(int i=0; i<m; ++i)
            cin >> come[i] >> num[i] >> wait[i] >> eat[i];

        multiset<Data> ms;
        ms.insert(Data(closeTime, -1, 3));
        for(int i=0; i<m; ++i){
            ms.insert(Data(come[i], i, 0));
            ms.insert(Data(come[i] + wait[i], i, 1));
        }

        queue<int> q;                         // 待っているグループ
        vector<pair<int, int> > sit(m);       // 各グループが使っているカウンターの位置
        vector<double> satisfaction(m, -1.0); // 各グループの満足度
        bool isClose = false;                 // 閉店時間を過ぎたかどうか
        while(!ms.empty()){
            long long time = ms.begin()->time;
            while(!ms.empty() && ms.begin()->time == time){
                Data d = *ms.begin();
                ms.erase(ms.begin());

                if(d.kind == 0){
                    q.push(d.id);
                }else if(d.kind == 2){
                    for(int i=0; i<num[d.id]; ++i)
                        used[sit[d.id].first][sit[d.id].second + i] = false;
                }else if(d.kind == 3){
                    isClose = true;
                }
            }
            if(isClose)
                break;

            while(!q.empty()){
                int id = q.front();
                if(time > come[id] + wait[id]){
                    q.pop();
                    continue;
                }

                pair<int, int> pos = findCounter(used, num[id]);
                if(pos.first == -1){
                    if(time == come[id] + wait[id]){
                        q.pop();
                        continue;
                    }
                    break;
                }

                q.pop();
                for(int i=0; i<num[id]; ++i)
                    used[pos.first][pos.second + i] = true;
                sit[id] = pos;
                satisfaction[id] = (wait[id] - (time - come[id])) / (double)wait[id];
                ms.insert(Data(time + eat[id], id, 2));
            }
        }

        double ret = 0.0;
        for(int i=0; i<m; ++i)
            ret += satisfaction[i] * num[i];
        ret /= accumulate(num.begin(), num.end(), 0);
        printf("%.10f\n", ret);
    }
}
accuracy: 1
time_ms: 1090
memory_kb: 2784
final_rank: 2

code_snippet: #include <iostream>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

class Event{
public:
	int time, group, type;
	Event(int t, int g, int p) : time(t), group(g), type(p) {}
	bool operator < (const Event &e) const { return make_pair(time,type) > make_pair(e.time,e.type); }
};

int main(){
	int n, m, t;
	int c[100], pos[10000], T[10000], P[10000], W[10000], E[10000];
	int seat[100][100];
	int left[100], right[100], seq[100];
	bool out[10000], in[10000];
	double score[10000];
	while(cin >> n >> m >> t, n){
		for(int i=0;i<n;i++) cin >> c[i];
		memset(pos, -1, sizeof(pos));
		memset(out,false,sizeof(out));
		memset(in, false,sizeof(in));
		memset(seat, -1, sizeof(seat));
		priority_queue<Event> qu;
		queue<int> wait;
		for(int i=0;i<m;i++){
			cin >> T[i] >> P[i] >> W[i] >> E[i];
			qu.push(Event(T[i],i,1));
			qu.push(Event(T[i]+W[i],i,3));
		}
		while(!qu.empty()){
			Event e = qu.top(); qu.pop();
			if(e.type == 0){
				for(int i=0;i<c[pos[e.group]];i++){
					if(seat[pos[e.group]][i] == e.group) seat[pos[e.group]][i] = -1;
				}
				if(e.time<t) qu.push(Event(e.time,-1,2));
			}
			if(e.type == 1){
				while(!wait.empty()&&out[wait.front()]){ wait.pop(); }
				if(wait.empty()){
					int idxA = -1, idxB = -1, mScore = -1, MScore = -1;
					for(int i=0;i<n;i++){
						if(c[i] < P[e.group]) continue;
						left[0] = seat[i][0]==-1 ? 10000 : -1;
						for(int j=1;j<c[i];j++){
							if(seat[i][j]!=-1) left[j] = -1;
							else if(left[j-1]==10000) left[j] = 10000;
							else left[j] = left[j-1]+1;
						}
						right[c[i]-1] = seat[i][c[i]-1]==-1 ? 10000 : -1;
						for(int j=c[i]-2;j>=0;j--){
							if(seat[i][j]!=-1) right[j] = -1;
							else if(right[j+1]==10000) right[j] = 10000;
							else right[j] = right[j+1]+1;
						}
						for(int j=0;j<c[i];j++){
							if(seat[i][j]!=-1) seq[j] = -1;
							else if(j==0) seq[j] = 0;
							else seq[j] = seq[j-1]+1;
						}
						for(int j=0;j+P[e.group]-1<c[i];j++){
							if(left[j]!=-1&&seq[j]+P[e.group]-1==seq[j+P[e.group]-1]){
								if(idxA == -1||make_pair(mScore,MScore)<make_pair(min(left[j],right[j+P[e.group]-1]),max(left[j],right[j+P[e.group]-1]))){
									idxA = i; 
									idxB = j; 
									mScore = min(left[j],right[j+P[e.group]-1]);
									MScore = max(left[j],right[j+P[e.group]-1]);
								}
							}
						}
					}
					if(idxA == -1) { wait.push(e.group); continue; }
					for(int i=0;i<P[e.group];i++) seat[idxA][idxB+i] = e.group;
					pos[e.group] = idxA;
					in[e.group] = true;
					score[e.group] = 1.0;
					qu.push(Event(e.time+E[e.group], e.group, 0));
				} else {
					wait.push(e.group);
				}
			}
			if(e.type == 2){
				while(!wait.empty()){
					if(out[wait.front()]){ wait.pop(); continue; }
					int group = wait.front();
					int idxA = -1, idxB = -1, mScore = -1, MScore = -1;
					for(int i=0;i<n;i++){
						if(c[i] < P[group]) continue;
						left[0] = seat[i][0]==-1 ? 10000 : -1;
						for(int j=1;j<c[i];j++){
							if(seat[i][j]!=-1) left[j] = -1;
							else if(left[j-1]==10000) left[j] = 10000;
							else left[j] = left[j-1]+1;
						}
						right[c[i]-1] = seat[i][c[i]-1]==-1 ? 10000 : -1;
						for(int j=c[i]-2;j>=0;j--){
							if(seat[i][j]!=-1) right[j] = -1;
							else if(right[j+1]==10000) right[j] = 10000;
							else right[j] = right[j+1]+1;
						}
						for(int j=0;j<c[i];j++){
							if(seat[i][j]!=-1) seq[j] = -1;
							else if(j==0) seq[j] = 0;
							else seq[j] = seq[j-1]+1;
						}
						for(int j=0;j+P[group]-1<c[i];j++){
							if(left[j]!=-1&&seq[j]+P[group]-1==seq[j+P[group]-1]){
								if(idxA == -1||make_pair(mScore,MScore)<make_pair(min(left[j],right[j+P[group]-1]),max(left[j],right[j+P[group]-1]))){
									idxA = i; 
									idxB = j; 
									mScore = min(left[j],right[j+P[group]-1]);
									MScore = max(left[j],right[j+P[group]-1]);
								}
							}
						}
					}
					if(idxA == -1) break;
					for(int i=0;i<P[group];i++) seat[idxA][idxB+i] = group;
					pos[group] = idxA;

					in[group] = true;
					score[group] = (T[group]+W[group]-e.time)/(double)W[group];
					qu.push(Event(e.time+E[group], group, 0));
					wait.pop();
				}
			}
			if(e.type == 3){
				if(in[e.group] == true) continue;
				out[e.group] = true;
				score[e.group] = -1.0;
				if(e.time<t) qu.push(Event(e.time,-1,2));
			}
		}
		double ans = 0.0;
		int sum = 0;
		for(int i=0;i<m;i++){
			ans += score[i]*P[i];
			sum += P[i];
		}
		printf("%.10lf\n", ans/sum);
	}
}
accuracy: 1
time_ms: 1760
memory_kb: 1904
final_rank: 4

code_snippet: #include<iostream>
#include<cassert>
#include<vector>
#include<map>
#include<cmath>
#include<algorithm>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define pb         push_back
#define ALL(C)    (C).begin(),(C).end()

typedef long long ll;

const int N = 100;
const int M = 10000;
const int dinf=20000;
const ll inf = (1LL)<<50;

class Seat{
public:
  int a,b;
  ll time;
  bool operator<(const Seat & t)const{
    return a < t.a;
  }
};

int ind,amax,amin,al,ar;

void update(int tindex,int l,int r,int posl,int posr){
  if (l > r)swap(l,r);
  
  if (ind==-1||
      (l>amin)||
      (l==amin&&r >amax)){
    //||(l==amin&&r==amax&&tindex < ind)||
    //(l==amin&&r==amax&&tindex==ind&&posl<al)){
    ind=tindex;
    amin=l;
    amax=r;
    al=posl;
    ar=posr;
  }
}

void makeupdate(int tindex,int b,int a,int cap,int req){
  int tmp = a-b-1;
  if (tmp < req)return;
  int val=tmp-req;
  int l,r;
  l=val/2;r=val/2;
//   if (tmp%2 == 1 && req%2 == 0){
//     r++;
//   }else if (tmp%2 == 0 && req%2 == 1){
//     r++;
//   }
  if (val%2 == 1)r++;
  update(tindex,l,r,b+1+l,a-1-r);
}

void check(int cap,vector<Seat> &info,int req,int tindex){
  if (info.size() == 0){
    if (req > cap)return;
    if(req-1<cap)update(tindex,dinf,dinf,0,req-1);
    return;
  }
  
  if (info[0].a >= req){
    update(tindex,dinf,info[0].a-req,0,req-1);
  }  

  rep(i,(int)info.size()-1){
    makeupdate(tindex,info[i].b,info[i+1].a,cap,req);
  }

  if (cap-info[info.size()-1].b-1 >=req){
    update(tindex,cap-req-info[info.size()-1].b-1,dinf,cap-req,cap-1);
  }
}

void getseat(int n,vector<Seat> *a,int *cap,int req){
  rep(i,n){
    if (cap[i]>=req)check(cap[i],a[i],req,i);
  }
}

double solve(int n,int *cap,ll cl,int m,ll *come,int *num,ll *wait,ll *eat){
  ll now=-1;
  int top=0;
  double sum=0,div=0;
  vector<Seat> seat[N];
  rep(i,m)div+=num[i];
  
  while(top < m){
    ll fast=inf;
    rep(i,n){
      rep(j,seat[i].size()){
	fast=min(fast,seat[i][j].time);
      }
    }
    
    if (now < come[top] && come[top] < fast){//arrive
      now=come[top];
    }else if (fast != inf && fast > come[top]+wait[top]){//leave from queue
      now=come[top]+wait[top];
      sum+=(-1)*num[top];
      top++;
    }else now = fast;////leave from seat
    
    //    cout << now <<" " << cl << endl;

    if (now >=cl)break;

    rep(i,n){
      for(int j=(int)seat[i].size()-1;j>=0;j--){
	if (seat[i][j].time <= now){
	  seat[i].erase(seat[i].begin()+j);
	}
      }
    }

//      rep(i,n){
//        rep(j,seat[i].size()){
//   	cout <<"seat info " <<i<<" " <<  seat[i][j].a <<" " << seat[i][j].b <<" " << seat[i][j].time<<endl;
//        }
//      }
       
    while(top < m){
      while(top<m){
	if (now > come[top]+wait[top]){
	  sum+=(-1)*num[top];
	}else break;
	top++;
      }
      
      if (top == m || now < come[top])break;
      
      ind=-1;
      getseat(n,seat,cap,num[top]);
      if (ind == -1)break;
      
      seat[ind].pb((Seat){al,ar,now+eat[top]});
      //      cout << top <<" can sit " << ind <<" " << al <<" " << ar <<" "<<
      //	now <<" " << now+eat[top] <<  endl;
      sort(ALL(seat[ind]));
      sum+=((wait[top]-(now-come[top]))/(double)wait[top])*num[top];
      top++;
    }
  }
  REP(i,top,m)sum+=(-1)*num[i];
  return sum/div;
}

main(){
  int n,m;
  ll t;
  int cap[N];
  int num[M];
  ll come[M],wait[M],eat[M];
  while(cin>>n>>m>>t && n){
    rep(i,n)cin>>cap[i];
    rep(i,m)cin>>come[i]>>num[i]>>wait[i]>>eat[i];
    printf("%.16lf\n",solve(n,cap,t,m,come,num,wait,eat));
  }
  return false;
}


/*
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
0 0 0 x x x 4 4 4 7  7  7     2  2  2  8  8  8     3  3  3  9  9  9     1  1  1  
*/
accuracy: 1
time_ms: 1190
memory_kb: 1428
final_rank: 1