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

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 阅读( ...) 评论( ...) 编辑 收藏
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值