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;
}