【牛客编程巅峰赛S1第5场】排队

排队

https://ac.nowcoder.com/acm/problem/207273

题目

银行有 个服务窗口,假设当前有 个人等待办理业务,那么这 个人会被顺序分配一个从 1 到 的号码。

等待办理业务的流程如下:
从第 1 号到第 号顺序的进行排队。
假设当前第 1 号到第 号都正在办理或已经办理完业务,且某个窗口 A 没有客人正在办理业务,那么第 号会马上到窗口 A 办理业务。
如果有多个这样的窗口,第 号会随意选择一个窗口。

在 0 时刻,有 个窗口都没有客人正在办理业务,而 个人正在等待办理业务。
假设第 号不管在哪个窗口办理业务,办理业务的时间都为

求:有多少对 ,满足 ,且第 号办理业务完成的时间严格大于第 号办理业务完成的时间。

解题思路

遍历 a,同时维护一个最小优先队列 pq,使用数组 t 记录每个人办理业务完成的时间。
队列 pq 表示当第 i 个人开始办理业务时,m 个窗口没有客人的时间。获取最早空闲的窗口,其时间为 pq.top(),那么第 i 个人到该窗口办理业务,其完成时间为 pq.top() + a[i],记录到 t[i] 中,并更新队列。

现在,求数组 t 中有多少个逆序对,此即为题目所求。

使用归并排序求逆序对

归并排序包含这样三个步骤:

  • 分解:待排序的区间为 ,令 ,我们把 分成
  • 解决:使用归并排序递归地排序两个子序列
  • 合并:把两个已经排好序的子序列 合并起来

在待排序序列长度为 1 的时候,递归开始回升,因为默认长度为 1 的序列是排好序的。

假设有两个已排序的序列 等待合并。
分别指向上述两个序列。当 小,但比 中的其他数大时, 贡献了 个逆序对。

例如,假设是
一开始用指针 指向 的头部, 指向 的头部。此时,,6 对逆序对总数的贡献为 0。
接着,,此时 12 小于 20,12 的贡献为 1。
接着,,此时 16 小于 20,16 的贡献为 1。
接着,,此时 24 小于 54,24 的贡献为 3。
总贡献为 0 + 1 + 1 + 3 = 5,即 5 对逆序对。

C++代码

class Solution {
    long long cnt;
    void merge(vector<long long>& t, int b, int mid, int e){
        if(b >= e)
            return;
        vector<long long> L(t.begin()+b, t.begin()+mid+1);
        vector<long long> R(t.begin()+mid+1, t.begin()+e+1);
        int i = 0;
        int j = 0;
        int k = b;
        while(i<L.size() && j<R.size()){
            if(L[i]<=R[j]){
                t[k] = L[i];
                cnt += j;
                ++i;
            }
            else{
                t[k] = R[j];;
                ++j;
            }
            ++k;
        }
        while(i<L.size()){
            cnt += j;
            t[k] = L[i];
            ++k;
            ++i;
        }
        while(j<R.size()){
            t[k] = R[j];
            ++k;
            ++j;
        }
    }
    void mergeSort(vector<long long>& t, int b, int e){
        if(b >= e)
            return;
        int mid = b + (e-b)/2;
        mergeSort(t, b, mid);
        mergeSort(t, mid+1, e);
        merge(t, b, mid, e);
    }
public:
    /**
     * 求解合法的(i,j)对的数量
     * @param n int整型 n个人
     * @param m int整型 m个窗口
     * @param a int整型vector 长度为n的vector,顺序表示1-n号客人的办理业务所需时间
     * @return long长整型
     */
    long long getNumValidPairs(int n, int m, vector<int>& a) {
        // write code here
        vector<long long> tmp(m, 0);
        priority_queue<long long, vector<long long>, greater<long long> > pq(tmp.begin(), tmp.end());

        vector<long long> t(n);
        for(int i=0; i<n; ++i){
            long long tmp = pq.top() + a[i];
            t[i] = tmp;
            pq.pop();
            pq.push(tmp);
        }
        cnt = 0;
        mergeSort(t,0,n-1);
        return cnt;
    }
};
全部评论

相关推荐

从小父母离异家里没人管,靠着心里的不安和学校的环境也算是坚持到了学有所成的地步。到了大学环境开始松散不知道该做什么,只觉得在不挂科的基础上能往上考多少就考多少,等到秋招来临才发现自己有多么幼稚无能,今年九月份初才发现自己原来连一个求职的方向都没有。因为之前做过前后端一体的课设,算是有过了解,而对于其他岗位连做什么都不知道,因此这一个半个月在越来越焦虑的同时埋头苦学,事到如今想要活下去我似乎只能走前端这条路了,9月初先是靠着虚假夸大能力的简历得到一些笔试来确定了考察的方向,有一个大厂的无笔试面试最终是拒绝了没有勇气去面对。然后在这个基础上埋头苦学,如今也算是搭好了自己前端学习的框架和思考的瞄,可以逐渐给自己扩展新的知识和能力了,但这并不是一件多好的事儿,因为我发现学的越多越焦虑,学的越多便越无力。因为我感觉我如今努力学习的知识都是竞争对手们早就掌握了的东西,我如今困惑追求答案的难题早就被别人解决。别人早就能得心应手地做出项目而我连思考都会卡壳,看着别人的笔试和面经上那些闻所未闻的题目,我才知道别人到底有多强而我有多幼稚,我什么时候才能达到别人那种堪称熟练的能力呢?而且网上的焦虑越多越多,即便是真有这么高的能力最后也大概落得一个低薪打工人的下场,我真的感到迷茫。秋招都快结束了,而我还在继续痛苦的学习之旅,这些天找前端面试发现似乎问的有些简单跟网上搜到的内容不符(可能因为并不是大厂),我是不是本来就没打算被招所以别人懒得细问呢?我不知道,我只能继续总结下去学习下去,不管如何我都要活下去,如果我能早一些准备就好了,如果暑假能意识到现在这个情况就好了,可惜没有如果。种下一棵树的最好时间是十年前,其次是现在,虽然我相信自己的学习能力,但已经错过了最好的时机,只能在焦虑与痛苦中每天坚持学下去。目前的路还有很长很长,先去把typescript看了,再去巩固vue3的基础,再去练习elementui的使用,如果这能找到实习的话就好了。接下来呢?去学uniapp和小程序,不管如何我都要对得起曾经努力的自己。即便我们都感到痛苦,但我心中还是希望我们都能靠自己的努力来获取自己想要的幸福。
紧张的牛牛等一个of...:在担心什么呢,有一手985的学历在,就算是小厂别人都会要的,咱们双非的人更多,多少还在沉沦的,怕什么了
一句话证明你在找工作
点赞 评论 收藏
分享
昨天 22:54
武汉大学 Java
点赞 评论 收藏
分享
评论
2
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务