1. 程式人生 > 實用技巧 >CSUST 4003-你真的會泡麵嗎?(優先佇列模擬)

CSUST 4003-你真的會泡麵嗎?(優先佇列模擬)

題目連結:http://acm.csust.edu.cn/problem/4003
CSDN食用連結:https://blog.csdn.net/qq_43906000/article/details/107739654

Description

高鐵上有\(n\)個人第\(i\)個人編號為\(i\)他在\(s_i\) 時刻想去泡泡麵,他泡麵所需時間為\(t_i\)

假設他們從座位到飲水機的時間可以忽略不計。不過只有一臺飲水機,所以他們要排隊泡麵。

特別的,泡麵可以分很多次泡完。比如你泡麵需要\(3min\),可以先泡\(1min\),那麼接下來你所需泡麵的時間為\(2min\)

泡麵機服務策略:

首先先來的人可以優先泡麵;對於同時到達的人,優先服務剩餘所需泡麵最短的人;對於剩餘時間相同的人,則優先服務編號較小的人。

意思就是如果某時刻來了某個人\(x\)泡麵所需時間比正在使用飲水機的人\(y\)剩餘泡麵所需時間要短,那麼\(x\)可以暫時請走\(y\),自己先服務。

\(n\)個人完成泡麵時間為\(e_i\) 。請輸出\(n\)個人的\(e_i-s_i-t_i\)之和,答案對1000000007取模
\(1\leq n\leq 1e5,1\leq s_i,t_i\leq 1e9\)

Input
第一行一個整數\(n\)

接下來nn行每行兩個整數,表示\(s_i,t_i\)

Output
一行一個整數表示答案。

Sample Input 1
3
0 5
1 2
2 1
Sample Output 1
4

Sample Input 2


4
0 5
1 2
0 2
1 2
Sample Output 2
10

Hint
對於樣例1:
\(e1=8,e2=3,e3=4,\sum_{i=1}^{n}e_i-s_i-t_i=8-0-5+3-1-2+4-2-1=4\)

emmm,不清楚這道題的本質,比賽的時候一直貪心QAQ。。。

後來在想了挺久之後才發現好像就是個模擬。。。我們先按照來的時間和泡的時間進行一下雙關鍵字排序。我們服務的既然是最短時間的人,那麼我們可以用一個優先佇列來維護當前每個人的剩餘時間。那麼可以模擬如下:

對於第一個人,它可以泡到第二個人來,或者直接泡完。如果它可以直接泡完的話,那麼我們就直接將答案加上結束時間,否則的話我們就將第一個人的時間減去已經泡了的時間再丟到佇列裡面去。如此迴圈下去直到所有的人都跑完了。那麼現在佇列裡面還有多少個人可以直接一個個取出來加就好了。其模擬程式碼如下:

int cnt=1;
ll ed=0;
priority_queue<ll,vector<ll>,greater<ll> >q;
q.push(person[1].ti);
ed=person[1].st;
ll ans=0;
while (!q.empty() || cnt<n) {
	if (q.empty()) {q.push(person[++cnt].ti); ed=person[cnt].ti;}
	ll u=q.top();
	q.pop();
	if (cnt<n) {
		ll st=person[cnt+1].st;
		if (st<ed+u) {
			q.push(ed+u-st);
			q.push(person[++cnt].ti);
			ed=st;
		} 
		else { ans=(ans+u)%mod; ed+=u;}
	} 
	else { ans=(ans+u)%mod; ed+=u;}
}

最後我們只需要將答案減去所有人的開始時間和泡的時間就好了。

以下是AC程式碼:

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

typedef long long ll;
const int mac=1e5+10;
const ll mod=1e9+7;

struct node
{
	ll st,ti;
	bool operator<(const node&a)const{
		if (st!=a.st) return st<a.st;
		if (ti!=a.ti) return ti<a.ti;
	}
}person[mac];

int main()
{
	int n;
	scanf ("%d",&n);
	for (int i=1; i<=n; i++){
		int st,ti;
		scanf ("%d%d",&st,&ti);
		person[i]=node{st,ti};
	}
	sort(person+1,person+1+n);
	int cnt=1;
	ll ed=0;
	priority_queue<ll,vector<ll>,greater<ll> >q;
	q.push(person[1].ti);
	ed=person[1].st;
	ll ans=0;
	while (!q.empty() || cnt<n){
		if (q.empty()) {q.push(person[++cnt].ti); ed=person[cnt].st;}
		ll u=q.top();
		q.pop();
		if (cnt<n) {
			ll st=person[cnt+1].st;
			if (st<ed+u){
				q.push(ed+u-st);
				q.push(person[++cnt].ti);
				ed=st;
			}
			else {ans=(ans+ed+u)%mod; ed+=u;}
		}
		else {ans=(ans+ed+u)%mod; ed+=u;}
	}
	ll sum=0;
	for (int i=1; i<=n; i++)
		sum=(sum+person[i].st+person[i].ti)%mod;
	ans=(ans-sum+mod)%mod;
	printf("%lld\n",ans);
	return 0;
}