【BZOJ2666】[cqoi2012]组装
Description
数轴上有m个生产车间可以生产零件。一共有n种零件,编号为1~n。第i个车间的坐标为xi,生产第pi种零件(1<=pi<=n)。你需要在数轴上的某个位置修建一个组装车间,把这些零件组装起来。为了节约运输成本,你需要最小化cost(1)+cost(2)+…+cost(n),其中cost(x)表示生产第x种零件的车间中,到组装车间距离的平方的最小值。
Input
输入第一行为两个整数n, m,即零件的种类数和生产车间的个数。以下m行每行两个整数xi和pi(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; }
时间: 2024-10-09 21:09:56