排队(牛客编程巅峰赛s1第五场C)
凯撒密码
https://ac.nowcoder.com/acm/contest/6488/A
排队
Problem:
牛妹在银行排队等号时,观察到以下场景。
银行有m个服务窗口,假设当前有n个人等待办理业务,那么这n个人会被顺序分配一个从1到n的号码。等待办理业务的流程如下:
从第1号到第n号顺序的进行排队。
假设当前第1号到第i-1号都正在办理或已经办理完业务,且某个窗口A没有客人正在办理业务,那么第i号会马上到窗口A办理他的业务。
如果有多个这样的窗口,第i号会随意选择一个窗口。在0时刻,牛妹观察到m个窗口都没有客人正在办理业务,而n个人正在等待办理业务。
为了简化问题,我们假设第i号不管在哪个窗口办理业务,办理业务的时间都为。
牛妹想知道有多少对(i,j),满足
,且第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%数据,
。
对于100%数据,
,
题解:
用优先队列模拟窗口排队计算每个人的结束时间,题中所求为完成时间数列的逆序数,数据范围到用归并排序计算逆序数。
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; } };