牛客编程巅峰赛S1第5场 - 青铜局 C题 - 排队

题目链接:https://ac.nowcoder.com/acm/contest/6488/C

Description

牛妹在银行排队等号时,观察到以下场景。
银行有m个服务窗口,假设当前有n个人等待办理业务,那么这n个人会被顺序分配一个从1到n的号码。

等待办理业务的流程如下:
从第1号到第n号顺序的进行排队。
假设当前第1号到第i-1号都正在办理或已经办理完业务,且某个窗口A没有客人正在办理业务,那么第i号会马上到窗口A办理他的业务。
如果有多个这样的窗口,第i号会随意选择一个窗口。
在0时刻,牛妹观察到m个窗口都没有客人正在办理业务,而n个人正在等待办理业务。
为了简化问题,我们假设第i号不管在哪个窗口办理业务,办理业务的时间都为ai。
牛妹想知道有多少对(i,j),满足1≤i<j≤n,且第i号办理业务完成的时间严格大于第j号办理业务完成的时间。

Sample Input
5,2,[1,3,2,5,4]
Sample Output
1
Interpretation
1号 开始办理时间 0 办理完成时间 12号 开始办理时间 0 办理完成时间 33号 开始办理时间 1 办理完成时间 3 (在1号办理完同时开始办理)
第4号 开始办理时间 3 办理完成时间 8 (在23号办理完同时开始办理)
第5号 开始办理时间 3 办理完成时间 7 (在23号办理完同时开始办理)
唯一一组满足题意的(i,j)对为(4,5)
Hint
对于30%数据,1≤n,m≤1000。
对于100%数据,1≤n,m≤1000001≤ai≤1e9
Solution

听了雨巨的讲解才会做!呜呜呜
显然我们首先要求出每个人办理业务完成的时间,那么我们用一个小根堆来维护即可。
接下来我们只需要求出逆序对的个数即可。
求逆序对的个数一般可以用归并排序树状数组很幸运我都不会,哭死
那么就让我们来写一下归并排序求逆序对的个数吧!(Ctrl CV大法)

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 ans;
       long long b[100010], t[100010];
       void merge(int L, int mid, int R) {
            long long p = L, q = mid + 1;
            for (int i = L; i <= R; i++) {
                if (p <= mid && (t[p] <= t[q] || q > R)) {
                    b[i] = t[p];
                    p++;
                }
                else {
                    b[i] = t[q];
                    q++;
                    ans+=mid - p + 1;//因为已排好序,当前位置大,后续的必定也大
                }
            }
            for (int i = L; i <= R; i++) t[i] = b[i];
        }
        void mergesort(int L, int R) {
            if (L >= R) return;
            int mid = (L + R) / 2;
            mergesort(L, mid);
            mergesort(mid + 1, R);
            merge(L, mid, R);//合并
        }
        long long getNumValidPairs(int n, int m, vector<int>& a) {
	        // write code here
	        priority_queue<long long, vector<long long>, greater<long long> > p;//小根堆
	for (int i = 0; i < min(n, m); i++) {
	        for (int i = 0; i < min(n, m); i++) {
	            t[i] = a[i];
	            p.push(t[i]);
	        }
	        for (int i = m; i < n; i++) {
	            long long temp = p.top();
	            p.pop();
	            t[i] = a[i] + temp;
	            p.push(t[i]);
	        }
	        ans = 0;
	        mergesort(0, n - 1);//归并排序
	        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值