题解 P1392 【取数】

· · 题解

介绍一道基本版题目序列合并

仔细分析有何不同?

注意到K<=M

那么

我们可以用一个数组记录前i个数组的最优K个值

并不断地与第i+1数组进行比较从而更新这K个数

从而将问题转化为序列合并去完成

那么 如何求取2个数组之间的最优K项呢?

假设堆中元素不足K个,直接入大根堆。

假设堆中元素已有K个

代码时间复杂度(最大次数):66334603(这不是电话号码)

据说计算机一秒内最多可以计算八千万次。

酱紫已有就可以以较慢的速度AC了(4089ms)

安利一下某不知名优化!

#pragma GCC optimize(5)

结果:(2546ms)

上代码

手写堆,勿嫌弃

#pragma GCC optimize(5)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long long INF=1e17;
int Num2,m,n,k,Map[805][805],b[8000];
int Ans[805];
void AddHeap(int x)
{
    int Now=++Num2;b[Num2]=x;
    while(Now>1&&b[Now]>b[Now/2])
    {
        swap(b[Now],b[Now/2]);Now/=2;
    }
}
void Delete()
{
    int Now=1,k;b[1]=b[Num2];Num2--;
    while(Now*2<=Num2)
    {
        if(b[Now*2]>b[Now*2+1]||Num2==2*Now)k=Now*2;else k=Now*2+1;
        if(b[Now]<b[k]){swap(b[Now],b[k]);Now=k;}else break;
    }
}
void DFS(int D)
{
    if(D==n+1)return;
    for(int i=1;i<=k;i++)
     {
        for(int j=1;j<=k;j++)
        {
            int x=Map[1][i]+Map[D][j];
            if(Num2<k)AddHeap(x);
            else
            {
                if(b[1]>x){Delete();AddHeap(x);}
                else break;
            }
        }
    }
    for(int i=k;i>=1;i--)Map[1][i]=b[1],Delete();
    DFS(D+1);
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int A[805];
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)scanf("%d",&A[j]);sort(A+1,A+1+m);
        for(int j=1;j<=m;j++)Map[i][j]=A[j];
    }
    DFS(2);
    for(int i=1;i<=k;i++)printf("%d ",Map[1][i]);puts("");
    return 0;
}