[牛客练习赛38E][乱搞]出题人的数组

Description

出题人有两个数组,A,B,请你把两个数组归并起来使得 c o s t
= ∑ i ∗ c i cost=∑i∗ci最小 归并要求原数组的数的顺序在新数组中不改变

输入描述:

第一行输入两个正整数n,m,分别表示数组A,B的长度 第二行输入n个正整数,表示数组A 第二行输入m个正整数,表示数组B

输出描述:

一个正整数,表示cost

输入

3 3
1 3 5
2 6 4

输出

75

备注:

数据范围: n,m<=100000 ai,bi<=100000

题解

这题直接自闭了…
想了两个dp然后发现状态是 n 2 n^2 n2的根本没法优化…自闭了自闭了
问了问OZY
开始就先把B接在A的后面,然后你显然每次是找一个前缀扔到A里面,并且需要满足不超过之前放的那个前缀的位置
那我们考虑他扔到的位置距离A的结束点的贡献,不妨设这个长度为 y y y,和为 s 2 s2 s2
这个前缀的长度为 x x x,和为 s 1 s1 s1
显然想要优秀的话,你要满足这个式子 y ∗ s 1 > x ∗ s 2 y*s1>x*s2 ys1>xs2
第一个是减少的贡献,第二个是增加的贡献
移项一下就可以知道,满足后面这个前缀的平均值比前面这个后缀的平均值大就是优秀的
那么由于最后的序列一定是一段A+一段B+一段A…这样的
所以你要满足这些A和这些B的段的平均值要递减
同时显然我们想让这个玩意尽量优秀的话,就要满足每次从B中拿出来的前缀的平均值尽量大
根据上面这些性质
你就把A和B分成若干段,满足平均值递减并且没有任何合并操作能使得某个段的平均值变大
然后直接按大小归并起来就可以了…

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair
#define pii pair
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=100005;
int a[MAXN],b[MAXN],n,m;
LL s1[MAXN],s2[MAXN];
struct node
{
	double cal;
	int l,r;
	node(){}
	node(int _l,int _r,double _cal){l=_l;r=_r;cal=_cal;}
};
node list[MAXN];int tp;
node list1[MAXN];int tp1;
int ans[2*MAXN],tt;
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++)a[i]=read(),s1[i]=s1[i-1]+a[i];
	for(int i=1;i<=m;i++)b[i]=read(),s2[i]=s2[i-1]+b[i];
	list[tp=1]=node(1,1,a[1]);
	for(int i=2;i<=n;i++)
	{
		double sum=a[i];int l=i,r=i;
		while(sum>=list[tp].cal&&tp)
		{
			sum=(double)(s1[i]-s1[list[tp].l-1])/(i-list[tp].l+1);
			l=list[tp].l;tp--;
		}
		list[++tp]=node(l,r,sum);
	}
	
	list1[tp1=1]=node(1,1,b[1]);
	for(int i=2;i<=m;i++)
	{
		double sum=b[i];int l=i,r=i;
		while(sum>=list1[tp1].cal&&tp1)
		{
			sum=(double)(s2[i]-s2[list1[tp1].l-1])/(i-list1[tp1].l+1);
			l=list1[tp1].l;tp1--;
		}
		list1[++tp1]=node(l,r,sum);
	}
	int u1=1,u2=1;
	for(int i=1;i<=tp1+tp;i++)
	{
		if((list[u1].cal<list1[u2].cal&&u2<=tp1)||u1>tp)
		{
			for(int j=list1[u2].l;j<=list1[u2].r;j++)ans[++tt]=b[j];
			u2++;
		}
		else
		{
			for(int j=list[u1].l;j<=list[u1].r;j++)ans[++tt]=a[j];
			u1++;
		}
	}
	LL sum=0;
	for(int i=1;i<=n+m;i++)sum+=(LL)i*ans[i];
	pr2(sum);
	return 0;
}

你可能感兴趣的:(乱搞,nowcoder)