【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
\]
好耶!(