备战蓝桥杯---多路归并与归并排序刷题

话不多说,直接看题

我们考虑一行一行合并,一共m次,我们合并两个并取前n小,那么我们怎么取?

我们采用分组的思想:

我们选第一列的min,然后把后面那个再纳入考虑,用优先队列实现即可。

下面是AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
typedef pair<int,int> pii;
int m,n;
int a[N],b[N],c[N];
void merge(){
    priority_queue<pii,vector<pii>,greater<pii> >heap;
    for(int i=0;i<n;i++) heap.push({a[0]+b[i],0});
    for(int i=0;i<n;i++){
        auto t=heap.top();
        heap.pop();
        int s=t.first,p=t.second;
        c[i]=s;
        heap.push({s-a[p]+a[p+1],p+1});
    }
    for(int i=0;i<n;i++) a[i]=c[i];
}
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>m>>n;
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        sort(a,a+n);
        for(int i=0;i<m-1;i++){
            for(int j=0;j<n;j++) scanf("%d",&b[j]);
            merge();
        }
        for(int i=0;i<n;i++) printf("%d ",a[i]);
        cout<<endl;
    }
}

首先我们把1放入丑数,令i,j,k指向它(代表2,3,5),然后我们选min的成1,变成2,此时i指向2,然后我们再从3,5,2*2中选min的3,此时j指向2,依次类推,每用一次就向后移一下。下面是AC代码:

cpp 复制代码
class Solution {
public:
    int getUglyNumber(int n) {
       vector<int> q(1,1);
       int i=0,j=0,k=0;
       while(--n){
           int t=min(q[i]*2,min(q[j]*3,q[k]*5));
           q.push_back(t);
           if(q[i]*2==t) i++;//这里若有两个都=x,两个指针都要移
           if(q[j]*3==t) j++;
           if(q[k]*5==t) k++;
       }
       return q.back();
    }
};

首先,两个数都从大到小排这样对于就是min,我们先考虑A1234B3241(离散化后)我们假设A不动,那么答案就是B的逆序对的数量,假如A可以动?因为此时两个逆序对之差就是B的逆序对,而假如要凑出答案,那么他们的逆序对一定为0,而每一次移动去1个逆序对,所以答案还是B的逆序对,跟进一步,假如A乱序?我们不妨做一个映射,把A的每一个数都映射为1234.。。然后换一下B即可。至于逆序对用树状数组即可,下面是AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=100010,mod=99999997;
int n;
int a[N],b[N],c[N],p[N],tr[N];
long long sum[100010];
void work(int a[]){//离散化
    for(int i=1;i<=n;i++) p[i]=i;
    sort(p+1,p+n+1,[&](int x,int y){
        return a[x]<a[y];
    });
    for(int i=1;i<=n;i++) a[p[i]]=i;
}
int lowbit(int x){
    return x&(-x);
}
void add(int x,int v){
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=v;
}
int query(int x){
    int res=0;
    for(int i=x;i;i-=lowbit(i)) res+=tr[i];
    return res;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    work(a),work(b);
    for(int i=1;i<=n;i++){
        c[a[i]]=i;
    }
    for(int i=1;i<=n;i++){
        b[i]=c[b[i]];
    }
    for(int i=1;i<=n;i++){
        sum[i]=query(n)-query(b[i]);
        add(b[i],1);
    }
    memset(tr,0,sizeof(tr));
    for(int i=n;i>=1;i--){
        sum[i]=(sum[i]+query(b[i]-1))%mod;
        add(b[i],1);
    }
    
    long long ans=0;
    for(int i=1;i<=n;i++) ans=(ans+sum[i]);
    cout<<ans/2%mod;
}
相关推荐
Python×CATIA工业智造1 小时前
详细页智能解析算法:洞悉海量页面数据的核心技术
爬虫·算法·pycharm
无聊的小坏坏2 小时前
力扣 239 题:滑动窗口最大值的两种高效解法
c++·算法·leetcode
黎明smaly2 小时前
【排序】插入排序
c语言·开发语言·数据结构·c++·算法·排序算法
YuTaoShao2 小时前
【LeetCode 热题 100】206. 反转链表——(解法一)值翻转
算法·leetcode·链表
YuTaoShao2 小时前
【LeetCode 热题 100】142. 环形链表 II——快慢指针
java·算法·leetcode·链表
CCF_NOI.2 小时前
(普及−)B3629 吃冰棍——二分/模拟
数据结构·c++·算法
运器1233 小时前
【一起来学AI大模型】支持向量机(SVM):核心算法深度解析
大数据·人工智能·算法·机器学习·支持向量机·ai·ai编程
Zedthm3 小时前
LeetCode1004. 最大连续1的个数 III
java·算法·leetcode
神的孩子都在歌唱3 小时前
3423. 循环数组中相邻元素的最大差值 — day97
java·数据结构·算法
YuTaoShao3 小时前
【LeetCode 热题 100】73. 矩阵置零——(解法一)空间复杂度 O(M + N)
算法·leetcode·矩阵