1 条题解
-
0
自动搬运
来自洛谷,原作者为

XG_Zepto
**搬运于
2025-08-24 21:41:43,当前版本为作者最后更新于2018-05-29 17:58:38,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
思路
推广个人博客【Codeforces 626E】 Simple Skewness / 题解
原题是这个:【Codeforces 626E】 Simple Skewness
题意:从数列里选出若干个数,使得他们的平均数减中位数最大。
这个问题有三个性质:
- 答案一定是非零数。因为你只选择一个数的时候,答案为0;
- 选出的数一定为奇数个。我们可以通过这个方法来证明:
假设原来我们选了个数,这些数升序排列是 ~ ,我们现在去掉这个数,答案一定不会变劣。
设原来的平均数为,平均数的增量为:$$ΔAverage=\frac{av*2k-a_{k+1}}{2k-1}-av $$
中位数的增量为:$$ΔMedian=a_k-\frac{a_k+a_{k+1}}{2}$$
整理得:$$ΔAverage - ΔMedian = \frac{2av+(2k-1)(a_{k+1}-a_k)-a_{k+1}}{2(2k-1)}$$
上式显然大于零,证毕。
- 选定中位数后,向选定数列中添加新数字,一定是选择了两边可选的最大数。不断添加新数字,平均数的变化是先增后减的,所以我们可以通过二分找到它的峰值。
结合以上三点,算法就非常地显然了:枚举每一个中位数,然后二分找到对应的平均数的最大值,更新答案。
代码
用VS写的,提交的时候要记得注释掉第一个库。
// Facer's Magic.cpp: 定义控制台应用程序的入口点。 // XG_Zepto, 5/25/2018 // All rights reserved. #include "stdafx.h" #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #define mid (l+(r-l)/2) #define ll long long #define maxn 1000005 ll s[maxn],a[maxn]; int n; double ans; using namespace std; ll sum(int x,int l){ return s[n]-s[n-l]+s[x]-s[x-l-1]; } int main(){ ios::sync_with_stdio(false); cin>>n; for (int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+1+n); for (int i=1;i<=n;i++) s[i]=s[i-1]+a[i]; for (int i=2;i<n;i++){ int l=1,r=min(n-i,i-1); while(l<r){ ll s1=sum(i,mid)*(2*mid+3); ll s2=sum(i,mid+1)*(2*mid+1); //为了避免精度问题,用乘法代替除法比较大小。 if (s1>s2){ r=mid; } else{ l=mid+1; if (s1==s2) break; } } if (1.0*sum(i,l)/(2*l+1)-a[i]>ans) ans=1.0*sum(i,l)/(2*l+1)-a[i]; } printf("%.2f",ans); //记得保留两位小数 return 0; }
- 1
信息
- ID
- 1818
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者