2018CCPC桂林 A(贪心,思维)

题目

分析:首先发现将大的数放在小的数前面结果更优,于是想到通过比较元素大小的方式将两个数组合并,大的放前面小的放后面,但很容易就能想到比这样合并更优的方案。一开始我是想先按这种方式进行合并,然后将最后未合并完的剩余数组元素向前推进插值,维护一个双端队列保存推进元素块的信息,借此更新答案,但写到一半想到了反例,又想了想感觉没有解决的办法,原因在于这种方式过于局部,很难顾及全局。如果要合并的两个数组原本就是单调不增序列那按照一开始的想法直接比较两数组元素大小进行合并就好了,这样最终答案是正确的。此时就可以开始乱想,如果想到平均值就好办了,通过类似单调栈的方式将原本数组划分为多个区块,满足区块的平均值单调不增,然后就可以按照一开始的想法合并数组了。然后我们大致证明一下可以感觉到这样最优的,即不存在交换两个元素使结果优于以这种方式合并数组的答案。

#include<cstdio>
#include<algorithm>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int N = 1e5 + 50;

int T, n, m;
int a[N], b[N], c[N << 1], id[N << 1];
pair<ll, int> da[N], db[N];

int main(){
    scanf("%d", &T);
    for(int ca = 1; ca <= T; ++ca){
        ll ans = 0;
        int len_a = 0, len_b = 0, x = 1, y = 1, tot = 0, dx = 0, dy = 0;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i){
            scanf("%d", &a[i]);  da[++len_a] = {a[i], 1};
            while(len_a > 1 && da[len_a].fi * da[len_a - 1].se > da[len_a - 1].fi * da[len_a].se){
                --len_a;
		da[len_a] = {da[len_a].fi + da[len_a + 1].fi, da[len_a].se + da[len_a + 1].se};
            }
        }
        for(int i = 1; i <= m; ++i){
            scanf("%d", &b[i]);  db[++len_b] = {b[i], 1};
            while(len_b > 1 && db[len_b].fi * db[len_b - 1].se > db[len_b - 1].fi * db[len_b].se){
                --len_b;
		db[len_b] = {db[len_b].fi + db[len_b + 1].fi, db[len_b].se + db[len_b + 1].se};
            }
        }        
        while(x <= len_a && y <= len_b){
            if(da[x].fi * db[y].se < db[y].fi * da[x].se){
                for(int i = 1; i <= db[y].se; ++i){
                    ++tot;
                    ans += 1LL * b[dy + i] * tot;
                }
                dy += db[y++].se;
            }
            else{
                for(int i = 1; i <= da[x].se; ++i){
                    ++tot;
                    ans += 1LL * a[dx + i] * tot;
                }
                dx += da[x++].se;
            }
        }
        while(x <= len_a){
            for(int i = 1; i <= da[x].se; ++i){
                ++tot;
                ans += 1LL * a[dx + i] * tot;
            }
            dx += da[x++].se;
        }
        while(y <= len_b){
            for(int i = 1; i <= db[y].se; ++i){
                ++tot;
                ans += 1LL * b[dy + i] * tot;
            }
            dy += db[y++].se;
        }
        printf("Case %d: %lld\n", ca, ans);
    }
    return 0;
}
posted @ 2020-12-14 22:29  のNice  阅读(185)  评论(0编辑  收藏  举报