[洛谷P1392] 取数

无法用复杂状态进行转移时改变计算方式;巧妙的整体考虑;压缩空间优化时间

传送门:$>here<$

题意

给出一个n*m矩阵,从每一行选一个数加起来,可以得到一个和。易知总共会有$n^n$个和,输出最小的k个。

数据范围:$n,m \leq 800,k \leq m$

Solution

问题的转化

可转化为序列合并问题

启示

问题的转化

转化

my code

第一行要特判

/*By DennyQi 2019*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 810;
const int INF = 0x3f3f3f3f;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
    int x = 0; int w = 1; register char c = getchar();
    for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int n,m,K;
int a[MAXN],b[MAXN],c[MAXN];
priority_queue <int, vector<int>, less<int> > H;
inline void Merge(){
    while(H.size()) H.pop();
    for(int i = 1; i <= m; ++i){
        H.push(a[1] + b[i]);
    }
    for(int i = 2; i <= m; ++i){
        for(int j = 1; j <= m; ++j){
            if(a[i]+b[j] < H.top()){
                H.pop();
                H.push(a[i]+b[j]);
            }
            else{
                break;
            }
        }
    }
    for(int i = m; i > 0; --i){
        c[i] = H.top();
        H.pop();
    }
}
int main(){
    n = read(), m = read(), K = read();
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= m; ++j){
            a[j] = read();
        }
        sort(a+1,a+m+1);
        if(i == 1){
            for(int j = 1; j <= m; ++j){
                b[j] = a[j];
            }
            continue;
        }
        Merge();
        for(int j = 1; j <= m; ++j){
            b[j] = c[j];
        }
    }
    for(int i = 1; i <= K; ++i){
        printf("%d ",b[i]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qixingzhi/p/10777633.html