BZOJ2428:[HAOI2006]均分数据——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=2428

https://www.luogu.org/problemnew/show/P2503

已知N个正整数:A1、A2、……、An 。今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小。均方差公式如下

BZOJ2428:[HAOI2006]均分数据——题解

其中σ为均方差,BZOJ2428:[HAOI2006]均分数据——题解是各组数据和的平均值,xi为第i组数据的数值和。

我们做过很多类似这样的题,首先将均方差式子展开就会发现答案是小是大只和sigma(xi^2)有关。

所以我们可以dp……等等,貌似这个序列可以任取啊……dp好像做不了。

于是我们乱搞模拟退火,每次对这个序列随机交换两个元素,然后dp check一下ans是否能变小就行了。

dp方程太简单了我就懒得写了。

#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long double dl;
const int N=;
const dl T=;
const dl eps=1e-;
const dl delta=0.998;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
int n,m,a[N],s[N],f[N][];
dl sum,rms,t,ans=9e18;
inline int sigma(int l,int r){
return (s[r]-s[l-])*(s[r]-s[l-]);
}
inline int suan(){
memset(f,,sizeof(f));
for(int i=;i<=n;i++){
s[i]=s[i-]+a[i];
f[i][]=sigma(,i);
for(int j=;j<=min(i,m);j++){
for(int k=;k<i;k++){
f[i][j]=min(f[i][j],f[k][j-]+sigma(k+,i));
}
}
}
return f[n][m];
}
void simulate_anneal(){
t=T;
while(t>eps){
int i=rand()%n+,j=rand()%n+;
swap(a[i],a[j]);
dl nans=suan();
dl dans=nans-ans;
if(nans<ans||rand()<exp(-dans/t)*RAND_MAX)ans=nans;
else swap(a[i],a[j]);
t*=delta;
}
}
int main(){
srand();
n=read();m=read();
for(int i=;i<=n;i++)a[i]=read(),sum+=a[i];
simulate_anneal();
rms=sum/m;
ans=sqrt((ans-rms*rms*m)/m);
printf("%.2Lf\n",ans);
return ;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

上一篇:MRJob 极速入门教程,使用Python玩转Hadoop


下一篇:高级SQL运用