[HAOI2006]均分数据
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLzkleNFzYU9UMNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2cDN3ATOxMjMzITMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
题解:
题目稍微解释一下:
把n个数以分为m组,计算每一组的和,求得到的这m个数的方差。由于分法是任意的,我们要求这些方差中的最小值
我们先用STL中的函数random_shuffle()用来对一个元素序列进行重新排序(随机的)
众所周知:如果每个组数的大小都相近的话,方差就越小
所以我们每次将第i个数加给当前数之和最小的那个组,这样操作可以使得在当前排列下,m组数最相近,也就是方差最小
循环个5e5次就够了,太多就会超时(5e6的话洛谷和牛客的机子都会超时)
貌似dp也可以做??
代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
return s*w;
}
const int maxn=100;
int a[maxn];
int x[maxn];
double tot;
double ans=0x3f;
int n,m;
inline void calc()
{
memset(x,0,sizeof(x));
for(int i=1;i<=n;i++)
{
int p=1;//第p组
for(int j=1;j<=m;j++){
if(x[j]<x[p])p=j;
}
x[p]+=a[i];//每次把数加给最小的组
}
double sum=0;
for(int i=1;i<=m;i++)
{
sum=sum+(x[i]-tot)*(x[i]-tot);
}
sum=sum/(double)m;
sum=sqrt(sum);
if(sum<ans)ans=sum;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
tot+=a[i];
}
tot/=(double)m;
int T=5000000;
while(T--)
{
random_shuffle(a+1,a+1+n);
calc();
}
printf("%.2f\n",ans);
}