[POI2003]Chocolate 题解
题目地址:BZOJ:Problem 2430. — [Poi2003]Chocolate
题目描述
有一块n*m的矩形巧克力,准备将它切成n*m块。巧克力上共有n-1条横线和m-1条竖线,你每次可以沿着其中的一条横线或竖线将巧克力切开,无论切割的长短,沿着每条横线切一次的代价依次为y1,y2,…,yn-1,而沿竖线切割的代价依次为x1,x2,…,xm-1。例如,对于下图6*4的巧克力,
我们先沿着三条横线切割,需要3刀,得到4条巧克力,然后再将这4条巧克力沿竖线切割,每条都需要5刀,则最终所花费的代价为y1+y2+y3+4*(x1+x2+x3+x4+x5)。
当然,上述简单切法不见得是最优切法,那么怎样切割该块巧克力,花费的代价最少呢?
题意简述
要把一个大矩形横着切n-1刀竖着切m-1刀分成n*m个小矩形,从左到右从上到下每个位置切一刀都有一个代价,每一次对一整块(不论大小,无法一刀切断多块)切一次都会产生一次代价,求切割的最小代价。
输入输出格式
输入格式:
第一行为两个整数n和m。
接下来n-1行,每行一个整数,分别代表x1,x2,…,xn-1。
接下来m-1行,每行一个整数,分别代表y1,y2,…,ym-1。
输出格式:
输出一整数,为切割巧克力的最小代价。
输入输出样例
输入样例#1:
6 4 2 1 3 1 4 4 1 2
输出样例#1:
42
说明
30%的数据,n<=100,m<=100
100%的数据,n<=10000,m<=10000
题解
贪心。
一定是先切掉代价较大的位置。考虑证明它,对于平行的刀切位置,在一个序列中先切代价大的,由于每一刀要乘上与位置垂直的位置已经切了几刀这个数字,因此越靠前乘的数字越小,总和越小。对于垂直的两个刀切位置,先切代价较大的那个,若先切较小的,较大的乘的数字会+1,比先切较大的更劣。
由于需要排序,复杂度O(n \log n)。
代码
// Code by KSkun, 2018/6
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
#include <functional>
typedef long long LL;
inline char fgc() {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
? EOF : *p1++;
}
inline LL readint() {
register LL res = 0, neg = 1; register char c = fgc();
for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
for(; isdigit(c); c = fgc()) res = (res << 1) + (res << 3) + c - '0';
return res * neg;
}
const int MAXN = 20005;
struct Node {
int w;
bool type;
inline bool operator>(const Node &rhs) const {
return w > rhs.w;
}
};
int n, m;
std::vector<Node> vec;
int main() {
n = readint(); m = readint();
for(int i = 1, t; i < n; i++) {
t = readint(); vec.push_back(Node {t, 0});
}
for(int i = 1, t; i < m; i++) {
t = readint(); vec.push_back(Node {t, 1});
}
std::sort(vec.begin(), vec.end(), std::greater<Node>());
int ch = 1, cv = 1, ans = 0;
for(int i = 0; i < vec.size(); i++) {
ans += vec[i].w * (vec[i].type ? ch : cv);
if(vec[i].type) cv++; else ch++;
}
printf("%d", ans);
return 0;
}