题目链接:
http://acm.sgu.ru/problem.php?contest=0&problem=114
题目的意思给定一些X[i] 和 P[i] ,要在X轴上取一点X是的 sum (abs(X[i] - X) * P[i]) 最小。
可以证明 X必然会为X[i] 中的某一个点,如果不然比如X落在 X[r] 和 X[r +1]之间,那么在X
左面的sum(P[i]) 和在X 右面的 sum(P[i]) 必然有一个值大或者小,或者两个相等,如果
有一个大,那么我们可以把X移到sum(P[i])大的那面的那个点上,可以取道更小的值,所以必然
可以将X 放在某一个X[i] 上使得所求的值最小。那么下面我们就可以按X[i]排序,然后O(n)的枚举
所放置的位置来求得答案。
代码如下:
const double eps = 1e-6;
const int MaxN = 15005;
int N,pos;
double ans;
const int INF = 0x7fffffff;
typedef struct A{
int X,P;
}A;
bool operator<(const A& a,const A& b){
return a.X < b.X;
}
A AA[MaxN];
void input(){
scanf("%d",&N);
for(int i = 0 ;i < N; ++i)
scanf("%d%d",&AA[i].X,&AA[i].P);
}
double calc(int pp){
double ret = 0;
for(int i = 0 ;i < N; ++i)
ret += fabs(AA[i].X *1.0 -pp)*AA[i].P;
return ret;
}
int solve(){
pos = 0;
int lnum = 0, rnum = 0;
for(int i = 1 ;i < N; ++i)
rnum += AA[i].P;
ans = calc(AA[0].X);
lnum = AA[0].P;
//cout<<"lnum = "<<lnum<<" "<<"rnum = "<<rnum<<endl;
for(int i = 1 ;i < N; ++i){
//long long tmp = calc(AA[i].X);
//cout<<"i = "<<i<<" "<<" tmp = "<<tmp <<endl;
double tmp = ans + 1.0*lnum *(AA[i].X - AA[i-1].X);
tmp -= (1.0*rnum ) * (AA[i].X - AA[i-1].X);
lnum += AA[i].P;
rnum -= AA[i].P;
//cout<<i<<" "<<tmp<<endl;
if(tmp < ans){
ans = tmp;
pos = i;
}
}
return pos;
}
int main(){
// ans = 200000000000000000LL;
//printf("INF = %d/n",INF);
input();
sort(AA,AA + N);
//printf("ret = %d/n",solve());
printf("%.5lf/n",(double)(AA[solve()].X));
return 0;
}