[atARC121D]1 or 2

对于大小为1的集合,我们可以在其中加入0

因此,枚举0的个数,那么问题即可以看作要求每一个集合大小为2

(特别的,我们允许存在${0,0}$,因为这样删除这两个0显然只会减小极差)

显然此时贪心将最小与最大、次小与次大……放入一个集合中即可

关于正确性,设最小值和最大值为$A,D$,若${A,D}$则继续归纳即可,否则若${A,B}$和${C,D}$,那么有
$$
egin{cases}min(A+D,B+C)ge min(A+B,C+D)\max(A+D,B+C)le max(A+B,C+D)end{cases}
$$
(关于这两个式子,左边的每一项都存在右边的一项小于等于或大于等于其)

因此不妨改为${A,D}$和${B,C}$,显然只会减小极差

具体实现可以先排序,再按照正负分开并加入0即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 5005
 4 vector<int>vn,vp;
 5 int n,mx,mn,ans,a[N];
 6 void add(int x){
 7     mx=max(mx,x);
 8     mn=min(mn,x);
 9 }
10 int main(){
11     scanf("%d",&n);
12     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
13     sort(a+1,a+n+1);
14     for(int i=1;i<=n;i++)
15         if (a[i]<=0)vn.push_back(a[i]);
16     for(int i=n;i;i--)
17         if (a[i]>0)vp.push_back(a[i]);
18     if (n&1)vn.push_back(0);
19     ans=2e9;
20     for(int i=(n&1);i<=n;i+=2,vn.push_back(0),vn.push_back(0)){
21         mx=-2e9,mn=2e9;
22         if (vn.size()<vp.size()){
23             for(int j=0;j<vn.size();j++)add(vn[j]+vp[j]);
24             for(int j=0;j<(vp.size()-vn.size())/2;j++)add(vp[vn.size()+j]+vp[vp.size()-j-1]);
25         }
26         else{
27             for(int j=0;j<vp.size();j++)add(vn[j]+vp[j]);
28             for(int j=0;j<(vn.size()-vp.size())/2;j++)add(vn[vp.size()+j]+vn[vn.size()-j-1]);
29         }
30         ans=min(ans,mx-mn);
31     }
32     printf("%d",ans);
33 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14971202.html