CF1400E - Clear the Multiset
思路
昨天模擬賽考慮一道NOIP2018T1變形,不會。今天又偶遇一道變形,成功被昨天帶偏,覺得肯定不是分治……
正解就是分治+貪心,每次選最小的群傷,然後分治到兩邊即可。
與 NOIP2018 不同的是整個區間 \([l, r]\) 也可以全部點殺掉,兩種情況要取 \(\min\)。
時間複雜度 \(O(n^2)\),瓶頸在預處理區間最小值。用 st 表可以做到 \(O(n \log n)\),用笛卡爾樹可以做到 \(O(n)\)。
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=(r);++i)
#define G(i,r,l) for(int i(r);i>=(l);--i)
#define pii pair<int, int>
#define fi first
#define se second
using namespace std;
using ll = long long;
const int N = 5005;
int a[N], mi[N][N], n;
int cmin(int i, int j){
if(a[i] < a[j]) return i;
return j;
}
int solve(int l, int r, int val){
if(l > r) return 0;
if(l == r && a[l] > val) return 1;
return min(r - l + 1, solve(l, mi[l][r] - 1, a[mi[l][r]]) + solve(mi[l][r] + 1, r, a[mi[l][r]]) + a[mi[l][r]] - val);
}
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n;
F(i, 1, n) cin >> a[i];
F(i, 1, n){
mi[i][i] = i;
F(j, i + 1, n) mi[i][j] = cmin(mi[i][j - 1], j);
}
cout << solve(1, n, 0) << '\n';
return fflush(0), 0;
}
總結
區間操作問題還是挺活的,還是說明得多積累經驗。