1. 程式人生 > 其它 >CF1006B Polycarp's Practice 題解

CF1006B Polycarp's Practice 題解

CF1006B Polycarp's Practice 題解

Content

給定一個長度為 \(n\) 的數列,試將其分成 \(k\) 段,使得每一段中的最大值的和最大。

資料範圍:\(1\leqslant k,n,a_i\leqslant 2000\)

Solution

我們不難發現,最優的方案其實就是將前 \(k\) 大的數各自單獨放在一段裡面,所以我們排序得到前 \(k\) 大的數,再找到他們的位置。那麼如何記錄每一段裡面的其他數呢?我的方案是,將前 \(k-1\) 大的數作為每一段的最後一個數儲存,剩下的那個數所在的段就是沒有被前面的 \(k-1\) 個段佔的部分,這下就可以輕鬆地解決問題了。

Code

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;

int a[2007], sum, n, k, ids[2007];
struct node {
	int val, id;
	bool operator < (const node& ou) const {return val > ou.val;}
}a1[2007];

int main() {
	scanf("%d%d", &n, &k);
	for(int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
		a1[i].val = a[i], a1[i].id = i;
	}
	sort(a1 + 1, a1 + n + 1);
	for(int i = 1; i <= k; ++i) ids[i] = a1[i].id, sum += a1[i].val;
	sort(ids + 1, ids + k + 1);
	printf("%d\n", sum);
	int lastans = 0;
	for(int i = 1; i < k; ++i) {printf("%d ", ids[i] - ids[i - 1]); lastans += ids[i] - ids[i - 1];}
	printf("%d", n - lastans);
	return 0;
}