【BZOJ2666】[cqoi2012]组装 贪心

【BZOJ2666】[cqoi2012]组装

Description

数轴上有m个生产车间可以生产零件。一共有n种零件,编号为1~n。第i个车间的坐标为xi,生产第pi种零件(1<=pi<=n)。你需要在数轴上的某个位置修建一个组装车间,把这些零件组装起来。为了节约运输成本,你需要最小化cost(1)+cost(2)+…+cost(n),其中cost(x)表示生产第x种零件的车间中,到组装车间距离的平方的最小值。

Input

输入第一行为两个整数nm,即零件的种类数和生产车间的个数。以下m行每行两个整数xipi(1<=pi<=n)。输入按照生产车间从左到右的顺序排列(即xi<=xi+1。注意车间位置可以重复)。输入保证每种零件都有车间生产。

Output

输出仅一行,即组装车间的最优位置(可以和某个生产车间重合),四舍五入保留四位小数。输入保证最优位置惟一。

Sample Input

3 5
-1 3
0 1
2 3
4 2
5 2

Sample Output

2.0000

题解:易证:如果已知每种零件生产车间的位置,那么组装车间的位置一定是它们的中点。(自己列列式子就知道了。)

那么我们只需要知道每种零件生产车间的位置即可,对于相邻的同种车间i和i+1,当pi<x<mid时选择i,当mid<x<pi+1时选择i+1,那么我们只需要把所有的中间点都拿出来排个序,扫一遍统计答案即可。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100010;
int n,m,tot;
double s1,s2,ans,minn;
double x[maxn],y;
int c[maxn],last[10010],pre[maxn];
struct node
{
	double pos;
	int nxt;
}p[maxn];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
	return ret*f;
}
bool cmp(node a,node b)
{
	return a.pos<b.pos;
}
int main()
{
	n=rd(),m=rd();
	int i;
	for(i=1;i<=m;i++)
	{
		x[i]=rd(),c[i]=rd();
		if(!last[c[i]])	s1+=x[i],s2+=x[i]*x[i];
		else	pre[i]=last[c[i]],p[++tot].pos=(x[i]+x[last[c[i]]])/2,p[tot].nxt=i;
		last[c[i]]=i;
	}
	sort(p+1,p+tot+1,cmp);
	ans=y=s1/n,minn=s2-2*s1*y+y*y*n;
	for(i=1;i<=tot;i++)
	{
		s2-=x[pre[p[i].nxt]]*x[pre[p[i].nxt]],s1-=x[pre[p[i].nxt]];
		s2+=x[p[i].nxt]*x[p[i].nxt],s1+=x[p[i].nxt];
		y=s1/n;
		if(minn>s2-2*s1*y+y*y*n)	minn=s2-2*s1*y+y*y*n,ans=y;
	}
	printf("%.4lf",ans);
	return 0;
}
posted @ 2017-08-24 20:35  CQzhangyu  阅读(369)  评论(0编辑  收藏  举报