[IOI2000]邮局
题目描述
高速公路旁边有一些村庄。高速公路表示为整数轴,每个村庄的位置用单个整数坐标标识。没有两个在同样地方的村庄。两个位置之间的距离是其整数坐标差的绝对值。
邮局将建在一些,但不一定是所有的村庄中。为了建立邮局,应选择他们建造的位置,使每个村庄与其最近的邮局之间的距离总和最小。
你要编写一个程序,已知村庄的位置和邮局的数量,计算每个村庄和最近的邮局之间所有距离的最小可能的总和。
输入格式
第一行包含两个整数:第一个是村庄VV的数量,第二个是邮局的数量PP,1 \leq P \leq 3001≤P≤300,P \leq V \leq 3000P≤V≤3000.
第二行包含VV个整数。这些整数是村庄的位置。对于每个位置XX,认为1 \leq X \leq 100001≤X≤10000。
输出格式
第一行包含一个整数SS,它是每个村庄与其最近的邮局之间的所有距离的总和。
输入输出样例
输入 #1
10 5 1 2 3 6 7 9 11 22 44 50
输出 #1
9
说明/提示
对于40%的数据,V \leq 300V≤300
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 }