排队
Problem:
牛妹在银行排队等号时,观察到以下场景。
银行有m个服务窗口,假设当前有n个人等待办理业务,那么这n个人会被顺序分配一个从1到n的号码。等待办理业务的流程如下:
从第1号到第n号顺序的进行排队。
假设当前第1号到第i-1号都正在办理或已经办理完业务,且某个窗口A没有客人正在办理业务,那么第i号会马上到窗口A办理他的业务。
如果有多个这样的窗口,第i号会随意选择一个窗口。在0时刻,牛妹观察到m个窗口都没有客人正在办理业务,而n个人正在等待办理业务。
为了简化问题,我们假设第i号不管在哪个窗口办理业务,办理业务的时间都为(a_i)。牛妹想知道有多少对(i,j),满足(leq i<jleq n),且第i号办理业务完成的时间严格大于第j号办理业务完成的时间。
Example:
input
5,2,[1,3,2,5,4]
output
1
note
第1号 开始办理时间 0 办理完成时间 1
第2号 开始办理时间 0 办理完成时间 3
第3号 开始办理时间 1 办理完成时间 3 (在1号办理完同时开始办理)
第4号 开始办理时间 3 办理完成时间 8 (在2和3号办理完同时开始办理)
第5号 开始办理时间 3 办理完成时间 7 (在2和3号办理完同时开始办理)
唯一一组满足题意的(i,j)对为(4,5)
Remark:
对于30%数据,(1leq n,m leq 1000)。
对于100%数据,(1leq n,m leq 100000),(1leq a_i leq 1e9)
题解:
用优先队列模拟窗口排队计算每个人的结束时间,题中所求为完成时间数列的逆序数,数据范围到(1e5)用归并排序计算逆序数。
Code:
class Solution {
public:
/**
* 求解合法的(i,j)对的数量
* @param n int整型 n个人
* @param m int整型 m个窗口
* @param a int整型vector 长度为n的vector,顺序表示1-n号客人的办理业务所需时间
* @return long长整型
*/
long long tm[111111];
priority_queue<long long,vector<long long>, greater<long long>> box;
void Union(int L,int R,int mid,long long &sum)
{
long long mm[111111];
int k=1,l=L,r=mid+1;
while(l<=mid&&r<=R){
if(tm[l]<=tm[r]){
mm[k++]=tm[l++];
}
else{
sum+=mid+1-l;
mm[k++]=tm[r++];
}
}
while(l<=mid)
mm[k++]=tm[l++];
while(r<=R)
mm[k++]=tm[r++];
for(int i=L,j=1;i<=R;i++,j++)
tm[i]=mm[j];
return;
}
void merge(int l,int r,long long &sum)
{
if(l==r)
return;
int mid=(l+r)/2;
merge(l, mid,sum);
merge(mid+1, r, sum);
Union(l, r, mid, sum);
}
long long getNumValidPairs(int n, int m, vector<int>& a) {
// write code here
for(int i=0;i<m;i++)
box.push(0);
for(int i=0;i<n;i++){
long long mm=box.top()+a[i];
tm[i+1]=mm;
box.pop();
box.push(mm);
}
long long ans=0;
merge(1, n, ans);
return ans;
}
};