3784. 【NOIP2014模拟8.19】邮局选址 (File IO): input:post.in output:post.out

 

Time Limits: 1000 ms  Memory Limits: 131072 KB  Detailed Limits  

Description

在 J 市的一条笔直的公路旁分布着 n 个村庄,每个村庄都有一个唯一的坐标 Xi,任意一对村庄的坐标不同。最近,J 市领导计划在村庄里新建 m 个邮局,而邮局在 n个村庄里的分布情况会影响到居民的便利程度。
设 m 个邮局分别建在 P1,P2,..,Pm 号村庄。每个村庄的村民都会找到与其距离最近的一个邮局,若有多个距离最近的则会任选一个,该村庄的便利度即为该村庄与其最近的邮局的距离,而所有村庄的便利度的和即为总便利度。
严格地讲,总便利度 C定义为
Σmin⁡{|Xi-XPj|  (1≤j≤m)}
现在,由你来安排邮局的建设位置。请计算最小的 C 是多少。

Input

第一行两个整数 n m
第二行递增的n 个整数,表示 X1..Xn

Output

一行一个整数,表示最小的 C

Sample Input

10 5
1 2 3 6 7 9 11 22 44 50

Sample Output

9

Data Constraint

对于30%的测试数据  n ≤ 10
对于60%的测试数据   n ≤ 50
对于100%的测试数据  1 ≤ n ≤ 300; 1 ≤ m ≤ 30; m ≤ n; 1 ≤ Xi ≤ 10000 

Hint

样例解释:建立在坐标为:2 7 22 44 50的位置
每个村庄的便利度分别为:1 0 1 1 0 2 4 0 0 0

 

反思

真的要好好反思。

比赛时想到了转移和状态, 却发现不知道初值怎么赋:

f[i][0]这个状态的值应该为多少 ? 

事实上吗这个状态是没有意义的。但是为了解决这个状态的值, 我还tm设了左右两个基准点, Wa是应该的。

其实预处理出f[i][1]就行了。

 

#include<bits/stdc++.h>
#define open(x) freopen(x".in", "r", stdin);freopen(x".out", "w", stdout)
#define mem(a, b) memset(a, b, sizeof(a))
#define mcy(a, b) memcpy(a, b, sizeof(a))
#define pf printf
#define sf scanf
#define fo(i, a, b) for( int i = a; i <= b; ++i) 
#define fown(i, a, b) for( int i = a; i >= b; --i)
#define em(p, x) for(int p=tail[x];p;p=e[p].fr)
#define wt(a, c, d, s) fo(i, c, d) pf((s), a[i]); puts("")
#define rd(a, c, d) fo(iii, c, d) in((a)[i])
#define N 310
#define inf 147483647
#define maxn 10010
using namespace std;

template<class T> 
T in(T &x) {
	x=0;
	char ch = getchar(); int f = 0;
	while(ch < '0' || ch > '9') f |= ch == '-', ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x<<1) + (x<<3) + ch - '0', ch = getchar();
	x = f ? -x : x;
	return x;
}

int n, m, a[N], ans, bz[N], f[N][N], g[maxn], num[maxn];

int abss(int x) {return x < 0 ? -x : x;}

int gsum(int x, int y) {return g[y] - g[x - 1];}
int get_num(int x, int y) {return num[y] - num[x -1];}


int main() {
	open("post");
	in(n), in(m);
	fo(i, 1, n) in(a[i]), (num[a[i]]++), (g[a[i]]+=a[i]);
	sort(a + 1, a + 1 + n);
	fo(i, 1, maxn) (num[i]+=num[i - 1]), (g[i]+=g[i - 1]);
	
	ans = inf;
	mem(f, 127);
	fo(i, 1, n) f[i][1] = a[i] * get_num(0, a[i] - 1) - gsum(0, a[i] - 1) - a[i] * get_num(a[i] + 1, a[n]) + gsum(a[i] + 1, a[n]);
	
	fo(i, 1, n) 
	  {
	  	int up = min(i, m);
	  	fo(j, 2, up) {
		  	fo(k, 1, i - 1) {
			  	int cost = f[k][j - 1];
			  	cost -= get_num(a[i], a[n]) * (a[i] - a[k]);
			  	int l = a[k], r = a[i], mid = l + r >> 1;
			  	
			  	cost -= gsum(mid + 1, a[i] - 1) - a[k] * get_num(mid + 1, a[i] - 1);
			  	cost += a[i] * get_num(mid + 1, a[i] - 1) - gsum(mid + 1, a[i] - 1);
			  	
			  	f[i][j] = min(f[i][j], cost);
			  }
		  }
	  }
	fo(i, m, n) ans = min(ans, f[i][m]);
	
	pf("%d\n", ans);
	
}

O(n ^3)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值