Codeforces 626E Simple Skewness(暴力枚举+二分)
E. Simple Skewness
Define the simple skewness of a collection of numbers to be the collection's mean minus its median. You are given a list of n (not necessarily distinct) integers. Find the non-empty subset (with repetition) with the maximum simple skewness.
The mean of a collection is the average of its elements. The median of a collection is its middle element when all of its elements are sorted, or the average of its two middle elements if it has even size.
The first line of the input contains a single integer n (1 ≤ n ≤ 200 000) — the number of elements in the list.
The second line contains n integers xi (0 ≤ xi ≤ 1 000 000) — the ith element of the list.
In the first line, print a single integer k — the size of the subset.
In the second line, print k integers — the elements of the subset in any order.
If there are multiple optimal subsets, print any.
4
1 2 3 12
3
1 2 12
4
1 1 2 2
3
1 1 2
2
1 2
2
1 2
In the first case, the optimal subset is , which has mean 5, median 2, and simple skewness of 5 - 2 = 3.
In the second case, the optimal subset is . Note that repetition is allowed.
In the last case, any subset has the same median and mean, so all have simple skewness of 0.
题目链接:http://codeforces.com/contest/626/problem/E
题意
给出n个数的集合,求一个 (平均数-中位数)最大 (偏度最大)的子集,输出子集元素个数和各个元素(任意顺序)。
分析
因为是子集,所以不一定是连续的序列。然后我们有下面几个结论。
1.最大偏度一定≥0
因为一个元素时,偏度为0。
2.最大偏度子集必定有元素个数为奇数个的。
证:
如果当元素个数是偶数2*k时偏度最大,我们证明它去掉一个元素a[k+1]不会更差。
子集里排好序分别是a[i]。除去a[k+1]其它数的平均值为av
新平均值-旧平均值=av-(av+a[k+1])/2=(av-a[k+1])/2
新中位数-旧中位数=a[k]-(a[k]+a[k+1])/2=(a[k]-a[k+1])/2
且有 旧平均值-旧中位数=(av+a[k+1])/2-(a[k]+a[k+1])/2=(av-a[k])/2≥0 (否则不可能偏度最大)
所以有 平均值增量-中位数增量=(av-a[k])/2≥0
所以新的偏度肯定不会更差。
3.平均值先递增后递减
因为是奇数个,所以枚举每个数做中位数,假如左右延伸长度为j,那么要使偏度更大,我们一定是每次选剩下的里面左边最大和右边最大的数。所以剩下的数越来越小,平均值增加得越来越少,而当前平均值越来越大,到某个峰值后平均值就开始减小了。
所以可以用二分法每次取中点和中点旁边一个点判断当前平均值在增加还是减小,增加就往右找,减小就往左找。
顺便吐槽一句:cf测评机不行啊,跑这个跑了大半个小时才跑完!!!
下面给出AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=200020; 5 inline int read() 6 { 7 int x=0,f=1; 8 char ch=getchar(); 9 while(ch<'0'||ch>'9') 10 { 11 if(ch=='-') 12 f=-1; 13 ch=getchar(); 14 } 15 while(ch>='0'&&ch<='9') 16 { 17 x=x*10+ch-'0'; 18 ch=getchar(); 19 } 20 return x*f; 21 } 22 int n; 23 ll s[N<<1],a[N<<1]; 24 int ansi=1,ansp; 25 double ans; 26 //最大偏度≥0,所以初始值就是只有第一个元素,偏度为0 27 ll sum(int i,int j) 28 { 29 return s[n]-s[n-j]+s[i]-s[i-j-1]; 30 } 31 int main() 32 { 33 n=read(); 34 for(int i=1;i<=n;i++) 35 cin>>a[i]; 36 sort(a+1,a+1+n); 37 for(int i=1;i<=n;i++) 38 { 39 s[i]=s[i-1]+a[i]; 40 } 41 for(int i=2;i<n;i++) 42 { 43 int l=1,r=min(i-1,n-i),m; 44 ll s1,s2; 45 while(l<r) 46 { 47 int mid=(l+r)/2; 48 s1=sum(i,mid)*(2*mid+3); 49 s2=sum(i,mid+1)*(2*mid+1); 50 if(s1>s2) 51 { 52 r=mid; 53 } 54 else 55 { 56 l=mid+1; 57 if(s1==s2) 58 break; 59 } 60 } 61 if(1.0*sum(i,l)/(2*l+1)-a[i]>ans) 62 { 63 ans=1.0*sum(i,l)/(2*l+1)-a[i]; 64 ansi=i; 65 ansp=l; 66 } 67 } 68 cout<<ansp*2+1<<endl; 69 cout<<a[ansi]<<" "; 70 for(int i=1;i<=ansp;i++) 71 { 72 cout<<a[ansi-i]<<" "<<a[n-i+1]<<" "; 73 } 74 cout<<endl; 75 return 0; 76 }
作 者:Angel_Kitty
出 处:https://www.cnblogs.com/ECJTUACM-873284962/
关于作者:阿里云ACE,目前主要研究方向是Web安全漏洞以及反序列化。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
欢迎大家关注我的微信公众号IT老实人(IThonest),如果您觉得文章对您有很大的帮助,您可以考虑赏博主一杯咖啡以资鼓励,您的肯定将是我最大的动力。thx.
我的公众号是IT老实人(IThonest),一个有故事的公众号,欢迎大家来这里讨论,共同进步,不断学习才能不断进步。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码),个人QQ和微信的二维码也已给出,扫描下面👇的二维码一起来讨论吧!!!
欢迎大家关注我的Github,一些文章的备份和平常做的一些项目会存放在这里。