2018CCPC桂林 A-Array Merge 贪心

2018CCPC桂林 A-Array Merge

题意

给定两个长度分别为\(n\)\(m\)的数组\(A\)\(B\),将这两个数组合并为一个数组\(C\),合并过程中原数组中的数字顺序不能改变,问\(\sum_{i=1}^{n+m}c_i \cdot i\)的最大值为多少。

\(n,m\le 10^5\)

分析

首先最大的数字一定是和前一个数字连续放的,那么我们可以将这两个数合并成一个块,这个块怎么和一个数字比较优先级呢,假设这个块中的两个数字为\(a\)\(b\),一个不相关的数字为\(x\),按\(abx\)的放置顺序的答案为\(a+2b+3x\),按\(xab\)的顺序放置答案为\(x+2a+3b\),这两种方案的答案差值为\(2x-a-b\),即我们只要比较\(x\)\(\frac{a+b}{2}\)的大小即可,将这个结论推广一下就是先放平均数较大的块最优,我们先将\(a\)中每个数字都当作一个大小为\(1\)的块,然后比较相邻的块的平均数大小,若后面的块的平均数大于前一个块,就合并两个块,直至无法合并,对\(b\)数组也分块,然后按平均数大小合并两个数组中的块并计算答案即可。

Code

#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<ll,ll>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=1e5+10;
const int inf=1e9;
int T;
int n,m;
ll a[N],b[N];
pii x[N],y[N];
int k1,k2;
int main(){
    ios::sync_with_stdio(false);
    //freopen("in","r",stdin);
    cin>>T;
    for(int cas=1;cas<=T;cas++){
        cin>>n>>m;
        rep(i,1,n) cin>>a[i];
        rep(i,1,m) cin>>b[i];
        k1=k2=0;
        for(int i=1;i<=n;i++){
            x[++k1]=mp(a[i],1);
            while(k1>1&&x[k1-1].fi*x[k1].se<x[k1].fi*x[k1-1].se){
                x[k1-1]=mp(x[k1-1].fi+x[k1].fi,x[k1-1].se+x[k1].se);
                --k1;
            }
        }
        for(int i=1;i<=m;i++){
            y[++k2]=mp(b[i],1);
            while(k2>1&&y[k2-1].fi*y[k2].se<y[k2].fi*y[k2-1].se){
                y[k2-1]=mp(y[k2-1].fi+y[k2].fi,y[k2-1].se+y[k2].se);
                --k2;
            }
        }
        int l=1,r=1,now=0,pos1=0,pos2=0;
        ll ans=0;
        while(l<=k1||r<=k2){
            if(l<=k1&&r<=k2){
                if(x[l].fi*y[r].se<y[r].fi*x[l].se){
                    for(int i=1;i<=y[r].se;i++){
                        ++now;++pos2;
                        ans+=b[pos2]*now;
                    }
                    ++r;
                }else{
                    for(int i=1;i<=x[l].se;i++){
                        ++now;++pos1;
                        ans+=a[pos1]*now;
                    }
                    ++l;               
                }
            }else if(l<=k1){
                for(int i=1;i<=x[l].se;i++){
                    ++now;++pos1;
                    ans+=a[pos1]*now;
                }
                ++l;
            }else{
                for(int i=1;i<=y[r].se;i++){
                    ++now;++pos2;
                    ans+=b[pos2]*now;
                }
                ++r;                
            }
        }
        cout<<"Case "<<cas<<": "<<ans<<'\n';
    }
    return 0;
}
posted @ 2020-11-17 19:29  xyq0220  阅读(466)  评论(0编辑  收藏  举报