题目大意:给定数轴上的m个点,共有n种颜色,要求在数轴上选定一个点,使这个点到每种颜色最近的点的平方和最小
初始将所有颜色最左侧的点作为最近点,然后不断选择【当前点与同种颜色下一个点的中点最靠左的点】进行替换,并更新ans
理性证明见http://www.cnblogs.com/jianglangcaijin/p/4204478.html
下面来个感性证明:
这不是显然么- -
考虑将组装车间从-∞移动到+∞ 初始选择最左侧的点作为最近点
那么移动的过程中一旦车间离同种颜色的下一个点更近 那么当前点当然要替换了
所以是按照当前点和同种颜色的下一个点的中点坐标从左到右替换嘛。。。
小心爆long long
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
struct abcd{
int pos,belong;
bool operator < (const abcd &a) const
{
if(belong!=a.belong)
return belong < a.belong;
return pos < a.pos;
}
}a[M];
struct _abcd{
int pre,next;
bool operator < (const _abcd &_) const
{
return pre+next < _.pre+_.next ;
}
}b[M];
int n,m,tot;
long double ans=1e18,ans_pos;
long long sum,square_sum;
int main()
{
int i;
cin>>n>>m;
for(i=1;i<=m;i++)
scanf("%d%d",&a[i].pos,&a[i].belong);
sort(a+1,a+m+1);
for(i=1;i<=m;i++)
{
if(a[i].belong!=a[i-1].belong)
sum+=a[i].pos,square_sum+=(long long)a[i].pos*a[i].pos;
else
b[++tot].pre=a[i-1].pos,b[tot].next=a[i].pos;
}
ans=square_sum-(long double)sum/n*sum;
ans_pos=(long double)sum/n;
sort(b+1,b+tot+1);
for(i=1;i<=tot;i++)
{
sum-=b[i].pre;
sum+=b[i].next;
square_sum-=(long long)b[i].pre*b[i].pre;
square_sum+=(long long)b[i].next*b[i].next;
long double temp=square_sum-(long double)sum/n*sum;
if(temp<ans)
ans=temp,ans_pos=(long double)sum/n;
}
cout<<fixed<<setprecision(4)<<ans_pos<<endl;
return 0;
}