CCPC2018 桂林 A: Array Merge(贪心、带权并查集合并)

时间限制: 1 Sec  内存限制: 128 MB
提交: 37  解决: 3
[提交] [状态] [命题人:admin]

题目描述

Given two arrays A, B of length n and m separately, you have to merge them into only one array C (of length n + m) obeying the rule that the relative order of numbers in the same original array does not change in the new array.
After merging, please calculate the  and output it.
If there are multiple costs, please output the minimum of them.

 

输入

The first line of input file contains an integer T (1≤T≤50), describing the number of test cases.
Then there are 3 T lines, with every three lines representing a test case.
The first line of the test case contains two integers n and m (1≤n,m≤105) as described above.
The second line of that contains n integers, ith of which represents the A[i].
The third line of that contains m integers, ith of which represents the B[i].
The numbers in both array have range in [0,108].
It is guaranteed that the sum of n + m in all cases does not exceed 106.

 

输出

You should output exactly T lines. For each case, print Case d: (d represents the order of test case)first and then print a number representing the minimum cost on the same line.

 

样例输入

2
2 2
5 3
4 5
3 3
1 3 5
2 6 4

样例输出

Case 1: 40
Case 2: 75

 

提示

Sample 1: Considering merging (5) (3) and [4] [5], we have following valid methods:
- (5) (3) [4] [5], 1 5 + 2 3 + 3 4 + 4 5 = 43
- (5) [4] (3) [5], 1 5 + 2 4 + 3 3 + 4 5 = 43
- (5) [4] [5] (3), 1 5 + 2 4 + 3 5 + 4 3 = 40
- [4] (5) (3) [5], 1 4 + 2 5 + 3 3 + 4 5 = 43
- [4] (5) [5] (3), 1 4 + 2 5 + 3 5 + 4 3 = 41
- [4] [5] (5) (3), 1 4 + 2 5 + 3 5 + 4 3 = 41
So the answer is the minimum of the numbers above, 40.

 
显然在没有顺序限制时,按从大到小的顺序组成新数组是最优的。在加入保持相对顺序不变的条件后,对于A、B中的最大值,在将它前面那个数加入新数组C后,应当立即把这个最大值加入C,那么就可以把最大值和其前面的数看作一个整体。
类似的,可以把A和B两个数组分块,对于分块后的集合,易证优先放平均数较大的集合更优
 
 
#include "bits/stdc++.h"

using namespace std;
const int maxn = 1e5 + 100;

struct node {
    double sum;
    int cnt;

    friend bool operator<(node a, node b) {
        return a.sum * b.cnt < a.cnt * b.sum;
    }

    friend node operator+(node a, node b) {
        return (node) {a.sum + b.sum, a.cnt + b.cnt};
    }
};

int a[maxn], b[maxn];
node S[maxn], T[maxn];
vector<int> c;

void add(int op, int from, int to) {
    for (int i = from; i <= to; i++) {
        if (op == 1) {
            c.push_back(a[i]);
        } else {
            c.push_back(b[i]);
        }
    }
}


int main() {
    freopen("in.txt", "r", stdin);
    int _, cnt = 0;
    scanf("%d", &_);
    int n, m;
    while (_--) {
        c.clear();
        scanf("%d %d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        for (int i = 1; i <= m; i++) {
            scanf("%d", &b[i]);
        }
        int tot1 = 0, tot2 = 0;
        for (int i = 1; i <= n; i++) {
            S[++tot1] = (node) {1.0 * a[i], 1};
            while (tot1 > 1 && S[tot1 - 1] < S[tot1]) {
                S[tot1 - 1] = S[tot1 - 1] + S[tot1];
                tot1--;
            }
        }
        S[++tot1] = (node) {-1.0, 1};
        for (int i = 1; i <= m; i++) {
            T[++tot2] = (node) {1.0 * b[i], 1};
            while (tot2 > 1 && T[tot2 - 1] < T[tot2]) {
                T[tot2 - 1] = T[tot2 - 1] + T[tot2];
                tot2--;
            }
        }
        T[++tot2] = (node) {-1.0, 1};
        int nows = 1, nowt = 1, fa = 1, fb = 1;
        while (nows < tot1 || nowt < tot2) {
            if (S[nows] < T[nowt]) {
                add(2, fb, fb + T[nowt].cnt - 1);
                fb = fb + T[nowt].cnt;

                nowt++;
            } else {
                add(1, fa, fa + S[nows].cnt - 1);
                fa = fa + S[nows].cnt;

                nows++;
            }
        }
        long long ans = 0;
        for (int i = 0; i < c.size(); i++) {
            ans = ans + (i + 1ll) * c[i];
        }
        printf("Case %d: %lld\n", ++cnt, ans);
    }
    return 0;
}
贪心

 

 
posted @ 2019-05-02 17:34  Albert_liu  阅读(611)  评论(0编辑  收藏  举报