原题描述:
Example
Input
1 5 2 3 1 4
Output
0 10 20 34 48
Note
The figure below describes the sample test case.
The only best selection for k=2 should choose the leftmost and the rightmost points,
while a possible best selection for k=3 could contain any extra point in the middle.
题意:
N个x坐标中选择K个,使得两两距离和相加最大。
所以一个很显然且显然正确的策略是一直从两边取,第一个最左边,第二个
最右边,第三个次左边(第三个次左边次右边产生的贡献是一样的)。
比赛的时候没想清楚怎么代码实现,交给大佬了,大佬代码能力真的强,
在题解代码中发现有几个考虑过程中的复杂计算因为左右坐标贡献相消所以不用再
考虑了。
代码实现:
#include <iostream>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <algorithm>
#define LL long long
#define inf 0x3f3f3f3f
#define ull unsigned long long
using namespace std;
const int N = 2e5 + 100;
const int M = 1e6 + 100;
LL arr[N],ans[N],psum[N],ssum[N];
int main() {
int t,n;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
memset(ans,0,sizeof(ans));
memset(arr,0,sizeof(arr));
memset(psum,0,sizeof(psum));
memset(ssum,0,sizeof(ssum));
arr[1]=1;
for(int i=2; i<=n; i++)
scanf("%I64d",&arr[i]),arr[i]+=arr[i-1];
for(int i=1; i<=n; i++)
psum[i]=psum[i-1]+(LL)(i-1)*(LL)(arr[i]-arr[i-1]);
for(int i=n; i>=1; i--)
ssum[i]=ssum[i+1]+(LL)(n-i)*(LL)(arr[i+1]-arr[i]);
ans[1]=0;
ans[2]=arr[n]-arr[1];
for(int i=3; i<=n; i++) {
int l,r;
if(i&1) {
l=i/2+1;
r=n+1-l+1;
ans[i]=ans[i-1];
ans+=psum[l]+ssum[r];
ans+=(LL)(n-r+1)*(arr[r]-arr[l]);
} else {
r=n-i/2+1;
l=n+1-r;
ans[i]=ans[i-1];
ans+=ssum[r]+psum[l];
ans+=(LL)l*(arr[r]-arr[l]);
}
}
for(int i=1; i<n; i++)printf("%I64d ",ans[i]);
printf("%I64d\n",ans[n]);
}
return 0;
}
THE END;