题意:
科学实验时,测量一个量需要多次测量取平均值。让你构造一个数组,长度等于输入的数组,其中的元素与原数组对应相等的个数最少,并且构造的数组范围应该小于等于原数组的范围,且平均值相等。原数组最大值与最小值的差小于等于2。
思路:
由于题中的限制条件原数组最大值与最小值的差小于等于2,那么就很好构造了。
1、极值差小于2时,构造的数组等于原数组。
2、极值差等于2时。由于平均值不变,那么就有两种构造方案:(1)将最大最小值合并为中间值。(2)将中间值分解为最大最小值。这样会得出2个ans。我们只需要输出ans最小的那一组解就可以了。
如果用数组存三个值的个数的话需要加一个偏移量。
代码:
输出占了很多行。。
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<algorithm>
#include<vector>
using namespace std;
#define inf 1<<29
int n,a[100005];
int vis1[200005],vis2[200005],vis3[200005];
int main()
{
while(~scanf("%d",&n))
{
int minn=inf,maxx=-inf;
memset(vis1,0,sizeof vis1);
memset(vis2,0,sizeof vis2);
memset(vis3,0,sizeof vis3);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
a[i]+=100000;
vis1[a[i]]++;
minn=min(minn,a[i]);
maxx=max(maxx,a[i]);
}
if(maxx-minn<2)
{
printf("%d\n",n);
int flag=0;
for(int i=0;i<n;i++)
{
if(flag) printf(" ");
flag=1;
printf("%d",a[i]-100000);
}
printf("\n");
continue;
}
memcpy(vis2,vis1,sizeof vis1);
memcpy(vis3,vis1,sizeof vis1);
int k=min(vis1[minn],vis1[maxx]);
vis2[minn+1]+=k*2;
vis2[minn]-=k;
vis2[maxx]-=k;
k=vis3[minn+1];
if(k%2) k--;
vis3[minn]+=k/2;
vis3[maxx]+=k/2;
vis3[minn+1]-=k;
int ans1=vis2[minn]+vis1[minn+1]+vis2[maxx];
int ans2=vis1[minn]+vis3[minn+1]+vis1[maxx];
if(ans1<ans2)
{
printf("%d\n",ans1);
int flag=0;
while(vis2[minn])
{
if(flag) printf(" ");
flag=1;
printf("%d",minn-100000);
vis2[minn]--;
}
while(vis2[minn+1])
{
if(flag) printf(" ");
flag=1;
printf("%d",minn+1-100000);
vis2[minn+1]--;
}
while(vis2[minn+2])
{
if(flag) printf(" ");
flag=1;
printf("%d",minn+2-100000);
vis2[minn+2]--;
}
}
else
{
printf("%d\n",ans2);
int flag=0;
while(vis3[minn])
{
if(flag) printf(" ");
flag=1;
printf("%d",minn-100000);
vis3[minn]--;
}
while(vis3[minn+1])
{
if(flag) printf(" ");
flag=1;
printf("%d",minn+1-100000);
vis3[minn+1]--;
}
while(vis3[minn+2])
{
if(flag) printf(" ");
flag=1;
printf("%d",minn+2-100000);
vis3[minn+2]--;
}
}
printf("\n");
}
return 0;
}