1. 程式人生 > 實用技巧 >Codeforces 1400E Clear the Multiset(貪心 + 分治)

Codeforces 1400E Clear the Multiset(貪心 + 分治)

連結:https://codeforces.com/problemset/problem/1400/E
來源:Codeforces

  思路:給你一個數組,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零後操作的最少的次數。首先如果我們只使用操作 2,那麼一個區間內最多操作 \(r - l + 1\) 次。如果操作 1 和 操作 2 一起使用,我們可以貪心 + 分治的方式來求出操作次數,如果現在是一個區間,那麼我們找到區間內最小的值 \(cnt1\),此時我們進行操作操作 1 的次數就是 \(cnt1\),當前這個位置的數字就歸零了,此時這個數字左右兩邊還有可能進行重複的操作,那麼當前操作的次數就是 cnt1 + 左右兩邊區間可以操作的次數,這個時候我們需要和只進行操作 2 進行比較,判斷那種方式可以得到最小的操作次數。如果在遞迴的過程中最後只是剩下一個不為 0 的數字,那麼我們進行一次操作 2。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 5e3 + 10;
int a[maxn];

int solve(int l, int r) {
	if(l > r) return 0;
	else if (l == r) {
		if(a[l] == 0) return 0;
		else return 1;
	} 
	int cnt1 = 1e9 + 10, mid;
	for(int i = l; i <= r; ++ i) {
		if(a[i] < cnt1) {
			cnt1 = a[i];
			mid = i;
		}	
	}
	for(int i = l; i <= r; ++ i) a[i] -= cnt1;
	return min(cnt1 + solve(l, mid - 1) + solve(mid + 1, r), r - l + 1);
}

int main() {
	int n; scanf("%d", &n);
	for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	int ans = solve(1, n);
	printf("%d\n", ans);
	return 0;
}