【2020.11.17提高组模拟】数数(cuvelia) 题解

【2020.11.17提高组模拟】数数(cuvelia) 题解

题目描述

给你一个长度为n的序列\(a_1...a_n\)。对于所有的\(k\in [1,n]\)选择序列中的\(k\)个数(下标为\(i_1,i_2...i_k\)),使得\(\sum_{l=1}^k\sum_{r=l}^k|a_{i_l}-a_{i_r}|\)最大,并对于每个\(k\)求出这个最大值。

\(n\le 3\times 10^5\)

\(|a_i|\le 10^6\)

题意分析

求从一个序列中有序地取出k个数后的最大值,该值为每个数减去其前面所有数的绝对值之和。

首先对原序列排序。排序不影响答案。

接着,显然取出最大和最小值一定没错的。

再依次从没有取出的数中,取最小的和最大的放在取出的序列中间。

这个又为什么是对的呢?

考虑现在要取出的数放到取出的序列中间时,左右各有\(lsize\),\(rsize\)个数,左右数字和各为\(lsum\),\(rsum\)

那么插入这个数\(x\)对答案的贡献为

\[(rsum-rsize*x)+(lsize*sum-lsum) \]

提取

\[(rsum-lsum)-(rsize-lsize)*x \]

这个式子同时解释了为什么整个取出序列必须时升序的,且要从最大值和最小值开始取数,以及为什么要尽量保持左右数的数量平均。

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#define debug printf("Now is %d\n",__LINE__);
using namespace std;

template<class T>inline void read(T&x)
{
    char ch=getchar();
    int fu;
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') fu=-1,ch=getchar(); 
    x=ch-'0';ch=getchar();
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    x*=fu;
}
inline int read()
{
	int x=0,fu=1;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-') ch=getchar();
    if(ch=='-') fu=-1,ch=getchar();
    x=ch-'0';ch=getchar();
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*fu;
}
int G[55];
template<class T>inline void write(T x)
{
    int g=0;
    if(x<0) x=-x,putchar('-');
    do{G[++g]=x%10;x/=10;}while(x);
    for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
}
LL a[1000010];
LL ansxb[1000][1000];
LL ans[1000];
int n; 
int main()
{
	freopen("cuvelia.in","r",stdin);
	freopen("cuvelia.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	sort(a+1,a+n+1);
	if(n<=5)
	{
		do
		{
			re LL now=0;
			for(re int i=1;i<=n;i++)
			{
				for(re int j=1;j<=i;j++) now+=abs(a[i]-a[j]);
				if(now>ans[i])
				{
					ans[i]=now;
					for(int j=1;j<=i;j++) ansxb[i][j]=a[j];
				}
			}
		}while(next_permutation(a+1,a+n+1));
		for(re int i=1;i<=n;i++)
		{
			cout<<ans[i]<<endl;
//			cout<<i<<":"<<ans[i]<<" = ";
//			for(re int j=1;j<=i;j++)
//			{
//				cout<<ansxb[i][j]<<" ";
//			}
//			cout<<endl;
		}
	}
	else
	{
		cout<<0<<endl;
		LL ans=a[n]-a[1];
		LL l=2,r=n-1,lsum=a[1],lsize=1,rsum=a[n],rsize=1;
		cout<<ans<<endl;
		for(re int i=3;i<=n;i++)
		{
			if(i&1)
			{
				ans+=rsum-rsize*a[l]-lsum+lsize*a[l];
				lsum+=a[l];
				lsize++;
				l++;
			}
			else
			{
				ans+=rsum-rsize*a[r]-lsum+lsize*a[r];
				rsum+=a[r];
				rsize++;
				r--;
			}
			write(ans);
		}
	}
	return 0;
}

结语

考试的时候不知道为什么脑子抽到了,用了\(cout\)来输出这\(3*10^5\)个答案。

然后就

\[100\Rightarrow70\\ Rank19\Rightarrow36 \]

好耶!(

posted @ 2020-11-18 10:02  Vanilla_chan  阅读(228)  评论(0编辑  收藏  举报