[IOI2000]邮局

题目描述

高速公路旁边有一些村庄。高速公路表示为整数轴,每个村庄的位置用单个整数坐标标识。没有两个在同样地方的村庄。两个位置之间的距离是其整数坐标差的绝对值。

邮局将建在一些,但不一定是所有的村庄中。为了建立邮局,应选择他们建造的位置,使每个村庄与其最近的邮局之间的距离总和最小。

你要编写一个程序,已知村庄的位置和邮局的数量,计算每个村庄和最近的邮局之间所有距离的最小可能的总和。

输入格式

第一行包含两个整数:第一个是村庄VV的数量,第二个是邮局的数量PP,1 \leq P \leq 3001P300,P \leq V \leq 3000PV3000.

第二行包含VV个整数。这些整数是村庄的位置。对于每个位置XX,认为1 \leq X \leq 100001X10000。

输出格式

第一行包含一个整数SS,它是每个村庄与其最近的邮局之间的所有距离的总和。

输入输出样例

输入 #1
10 5 
1 2 3 6 7 9 11 22 44 50
输出 #1
9

说明/提示

对于40%的数据,V \leq 300V300

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 typedef long long ll;
 7 ll inf,a[3010];
 8 int n,m,p[3010][3010];
 9 ll sum[3010],f[3010][310];
10 ll get(int x,int y)
11 {
12     if (x>=y) return 0;
13     int mid=(y+x)/2;
14     return sum[y]-sum[mid]-1ll*(y-mid)*a[mid]+1ll*(mid-x)*a[mid]-sum[mid-1]+sum[x-1];
15 }
16 int main()
17 {int i,j,k;
18     scanf("%d%d",&n,&m);
19     for (i=1;i<=n;i++)
20     {
21         scanf("%lld",&a[i]);
22     }
23     sort(a+1,a+n+1);
24     for (i=1;i<=n;i++)
25     sum[i]=sum[i-1]+a[i];
26     memset(f,0x3f,sizeof(f));
27     inf=f[0][0];
28     for (i=1;i<=m;i++)
29     f[i][i]=0,p[n+1][i]=n;
30     for (i=1;i<=n;i++)
31     f[i][1]=get(1,i),p[i][1]=0;
32     for (i=2;i<=m;i++)
33     { 
34         for (j=n;j>i;j--)
35         {
36             for (k=p[j][i-1];k<=p[j+1][i];k++)
37             {
38                 if (k+1>j) continue;
39                 ll t=f[k][i-1]+get(k+1,j);
40                 if (f[j][i]>t)
41                 {
42                     f[j][i]=t;
43                     p[j][i]=k;
44                 }
45             }
46         }
47     }
48     printf("%lld\n",f[n][m]);
49 } 

 

posted @ 2020-01-30 20:08  Z-Y-Y-S  阅读(193)  评论(1编辑  收藏