[题解]CQOI2012 T2 组装 assemble
组装 assemble
【题目描述】
数轴上有m个生产车间可以生产零件。一共有n种零件,编号为1~n。第i个车间的坐标为xi,生产第pi种零件(1<=pi<=n)。你需要在数轴上的某个位置修建一个组装车间,把这些零件组装起来。为了节约运输成本,你需要最小化cost(1)+cost(2)+…+cost(n),其中cost(x)表示生产第x种零件的车间中,到组装车间距离的平方的最小值。
【输入】
输入第一行为两个整数n, m,即零件的种类数和生产车间的个数。以下m行每行两个整数xi和pi(1<=pi<=n)。输入按照生产车间从左到右的顺序排列(即xi<=xi+1。注意车间位置可以重复)。输入保证每种零件都有车间生产。
【输出】
输出仅一行,即组装车间的最优位置(可以和某个生产车间重合),四舍五入保留四位小数。输入保证最优位置惟一。
【样例】
assemble1.in
3 5
-1 3
0 1
2 3
4 2
5 2
assemble1.out
2.0000
assemble2.in
4 8
-10 2
-8 1
-5 1
-1 3
3 4
4 3
6 2
9 4
assemble2.out
0.7500
【数据规模】
编号 | 1-4 | 5-10 |
n | <=15 | <=10000 |
m | <=25 | <=100000 |
xi | <=100 | <=100000 |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
【题解】
还是一道比较简单的题目,感觉是在考数感。。注意题目要求的最终答案相当于是使选出的n个数的方差的n倍最小的位置。对于方差由两个公式,这里我用的第二个公式,方便维护。给出维基上方差的链接:http://zh.wikipedia.org/wiki/%E6%96%B9%E5%B7%AE
用一个结构体数组a[]保存一个伪链表。包括两个关键字,第一个为生产某种零件的车间位置,第二关键字为生产同种零件的下一个车间的位置。然后排序,按照两个关键字之和从小到大排序,即按照它们的终点坐标排序。(为什么自己想)默认第一次选出的n个车间为生产每一种零件的第一个车间,计算出总花费以及位置,然后从前往后扫a[],依次改变某一个车间的位置,更新总花费。
不多赘述了,个人认为代码写得还不错。望引玉>_<
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 #define MAXM 100020
7 #define MAXN 10020
8 typedef long long llt;
9 int n,m;
10 struct node
11 {
12 llt x,next;
13 };
14 node a[MAXM];
15 int In;
16 int Pos[MAXN],INF;
17 llt Sum1,Sum2;
18 bool Cmp(node a,node b)
19 {
20 return (a.x+a.next)<(b.x+b.next);
21 }
22 inline void Get_int(int &Ret)
23 {
24 char ch;
25 bool flag=false;
26 for(;ch=getchar(),ch<'0'||ch>'9';)
27 if(ch=='-')
28 flag=true;
29 for(Ret=ch-'0';ch=getchar(),ch>='0'&&ch<='9';Ret=Ret*10+ch-'0');
30 flag&&(Ret=-Ret);
31 }
32 void Read()
33 {
34 Get_int(n);
35 Get_int(m);
36 int i,xi,pi;
37 memset(Pos,0x3f,sizeof(Pos));
38 INF=Pos[0];
39 for(i=1;i<=m;i++)
40 {
41 Get_int(xi);
42 Get_int(pi);
43 if(Pos[pi]==INF)
44 {
45 Sum1+=xi;
46 Sum2+=xi*xi;
47 }
48 else
49 {
50 a[++In].x=Pos[pi];
51 a[In].next=xi;
52 }
53 Pos[pi]=xi;
54 }
55 sort(a+1,a+1+In,Cmp);
56 }
57 void Work()
58 {
59 //fang cha >_< _______orz
60 llt tmp=(llt)n*Sum2-Sum1*Sum1,_tmp;
61 //tmp=Sum2-(Sum1/n*Sum1/n)*n;
62 llt ans=Sum1;
63 //ans=Sum1/n;
64 int i;
65 for(i=1;i<=In;i++)
66 {
67 if(a[i].x==a[i].next)
68 continue;
69 Sum1+=(a[i].next-a[i].x);
70 Sum2+=(a[i].next*a[i].next-a[i].x*a[i].x);
71 _tmp=n*Sum2-Sum1*Sum1;
72 if(tmp>_tmp)
73 {
74 tmp=_tmp;
75 ans=Sum1;
76 }
77 }
78 printf("%.4lf\n",(double)ans/(double)n);
79 }
80 int main()
81 {
82 //freopen("assemble.in","r",stdin);
83 //freopen("assemble.out","w",stdout);
84 Read();
85 Work();
86 return 0;
87 }