Codeforces_Round_#622(Div. 2)_C.Skyscraper_非官方解法

題意: 給了一堆樓 要求 不能存在 i < j < k 時, 出現 aia_i > aja_j < aka_k 的情況 不一定非要挨着 樓高有限制 不得超過mim_i

官方題解是

單調棧 正着一遍 反着一遍就可以了
正着:dp[i]前i個保持遞增序列的最大前綴和
反着就遞減的最大後綴和
然後on掃最大

我的ST表 + (貪心)分治

找到最小值 要麼左邊全是最小值 要不就是右邊
選擇 一個 (rmins.second)mins.first+s1+mins.first(r - mins.second) * mins.first + s1 + mins.first(mins.secondl)mins.first+s2+mins.first(mins.second - l) * mins.first + s2 + mins.first 一個比較大的固定 貪心的選取它 接着分治另一邊
由於最小的已經固定 所以另一邊不考慮固定邊可能會影響

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 5e5 + 5;

int lg[maxn];
int a[maxn], b[maxn];
pair<int, int> f[maxn][30];
int n, m;

void ST_build() {
    for(int i = 1; i <= n; i ++ ) f[i][0] = make_pair(a[i], i);
    int t = (lg[n]-1)/(lg[2]-1) + 1;
    for(int j = 1; j < t; j ++ ) {
        for(int i = 1; i <= n - (1 << j) + 1; i ++ ) {
            f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
        }
    }
}

pair<int, int> ST_query(int l, int r){
    int k = (lg[r - l + 1] - 1);
    return min(f[l][k], f[r - (1 << k) + 1][k]);
}

int solve(int l, int r) {
	if(l > r) return 0;
	if(l == r) return b[l] = a[l];
	pair<int, int> mins = ST_query(l, r);
	int s1 = solve(l, mins.second - 1);
	int s2 = solve(mins.second + 1, r);
	if((r - mins.second) * mins.first + s1 > (mins.second - l) * mins.first + s2) {
		for(int i = mins.second; i <= r; i ++) b[i] = mins.first;
		return (r - mins.second) * mins.first + s1 + mins.first;
	} else {
		for(int i = l; i <= mins.second; i ++) b[i] = mins.first;
		return (mins.second - l) * mins.first + s2 + mins.first;
	}
}

signed main() {
	ios::sync_with_stdio(false), cin.tie(0);
	memset(f, 0x3f, sizeof(f));
	for(int i = 1; i < maxn; i ++){
        lg[i] = lg[i - 1] + ((1 << lg[i - 1]) == i);
    }
	cin >> n;
	for(int i = 1; i <= n; i ++) cin >> a[i];
	ST_build();
	solve(1, n);
	for(int i = 1; i <= n; i ++) cout << b[i] << " ";
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章