Codeforces Round 1039 (Div. 2)


A. Recycling Center

题意:给你一个数组\(a\),和一个数\(c\),每次选一个数,如果这个数小于等于\(c\)没有代价,否则有\(1\)的代价,没选一个数其它数乘二,求最小代价。

\(n\)很小,考虑倒着来,把所有数都乘上\(2^{n-1}\),初始代价为\(n\),如果有小于等于\(c\)的选最大的,然后代价减一,在把所有数除二,这样模拟\(n\)次就行了。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n, c;
	std::cin >> n >> c;
	std::vector<i64> a(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
		a[i] *= 1 << (n - 1);
	}

	std::ranges::sort(a);
	int ans = n;
	for (int i = 0; i < n; ++ i) {
		int k = -1;
		for (int j = 0; j < n; ++ j) {
			if (a[j] != -1 && a[j] <= c) {
				if (k == - 1 || a[k] < a[j]) {
					k = j;
				}
			}
		}

		if (k != -1) {
			-- ans;
			a[k] = -1;
		}

		for (int j = 0; j < n; ++ j) {
			if (a[j] != -1) {
				a[j] /= 2;
			}
		}
	}

	std::cout << ans << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

B. Deque Process

题意:一个排列是好的,那么它没有长度大于等于\(5\)的连续子序列递减或递增。给你一个排列,每次从左拿数或者从右拿数,使得最终得到一个好的排列。

第奇数次拿大的,偶数次拿小的。
我也不会证明,模拟一下发现没两三轮就和从递减变成递增或者从递增变成递减。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::vector<int> a(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

	std::string s;
	int l = 0, r = n - 1;
	int k = 0;
	while (l <= r) {
		if (k & 1) {
			if (a[l] > a[r]) {
				s += "L";
				++ l;
			} else {
				s += "R";
				-- r;
			}
		} else {
			if (a[l] < a[r]) {
				s += "L";
				++ l;
			} else {
				s += "R";
				-- r;
			}
		}
		++ k;
	}
	std::cout << s << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

C. Leftmost Below

题意:给你一个全\(0\)数组\(a\),每次选择一个大于\(min(a)\)的数\(x\),然后把小于\(x\)的最小位置加上\(x\)。求\(a\)能不能变成\(b\)

除了\(b_i = 1\)的位置,如果我们想让\(a_i = b_i\),那么\([1, i - 1]\)都应该满足了,则我们只能操作\(x\in [1, min_{i-1}\)],其中\(min_{i-1}\)\([1, i -1]\)的最小值。那么最多使得\(a_i\)变成\(min_{i-1} + min_{i-1} - 1\)。如果\(a_i \geq 2\times min_{i-1}\)无解。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::vector<int> b(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> b[i];
	}

	for (int i = 0, min = 1e9; i < n; ++ i) {
		if (min + min - 1 < b[i]) {
			std::cout << "NO\n";
			return;
		}
		min = std::min(min, b[i]);
	}
	std::cout << "YES\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

D. Sum of LDS

题意:一个排列,满足\(max(p_i, p_{i+1}) > p_{i+2}\)。求所有子数组的最长递减子序列。

直接算肯定不行,我们只能观察这个给出的性质。
我们发现最长上升连续子序列长度最多为\(2\),设\(p_i < p_{i+1}\),那么\(p_{i+2} < \max(p_i, p_{i+1})\),无法继续递增。
继续观察,发现除了这些递增子序列的位置,其它位置从左到右整体就是递减的。
每个子区间如果出现一个\(p_i < p_{i+1}\),那么最长递减子序列长度减少\(1\)。如果\(p_i < p_{i+1}\),那么有\(p_{i+2} < \max(p_i, p_{i+1}) < p_{i-1}\)

则我们考虑减去这些\(p_i < p_{i+1}\)的贡献,一开始长度为\(k\)的子数组最长递减子序列长度就是\(k\),那么有\(\sum_{k=1}^{n} k\times(n-k+1) = \frac{n(n+1)(n+2)}{6}\),这个也可以循环算。
然后对于每个\(p_i < p_{i+1}\),包含它们的区间有\(i\times(n-i)\)个。减去即可。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::vector<int> a(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

	i64 ans = 1LL * n * (n + 1) * (n + 2) / 6;
	for (int i = 0; i + 1 < n; ++ i) {
		if (a[i] < a[i + 1]) {
			ans -= (i64)(i + 1) * (n - i - 1);
		}
	}
	std::cout << ans << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

E1. Submedians (Easy Version)

题意:给你一个数组。求一个最大的\(x\),使得有一个长度大于等于\(k\)的子区间的中位数是\(x\)

这个题貌似太典了,印象中光\(cf\)就出过好几次吧。
如果一个数小于等于数组里的中位数,那么把小于它的设置为\(-1\),大于等于它的设置为\(1\),那么如果有一个区间的和大于等于\(0\)则满足条件。
那么考虑二分中位数,求有没有区间的中位数大于等于\(mid\)。这里要求长度大于等于\(k\),那么就只记录比当前位置小\(k\)的位置的前缀和就行了。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
    int n, k;
    std::cin >> n >> k;
    std::vector<int> a(n + 1);
    for(int i = 1; i <= n; ++ i){
        std::cin >> a[i];
    }

    auto check = [&](int v) -> std::tuple<bool, int, int> {
        static std::vector<int> S;
        S.resize(n + 1);
        S[0] = 0;
        for(int i = 1; i <= n; ++ i){
            S[i] = S[i - 1] + (a[i] >= v ? 1 : -1);
        }

        int tl, tr;
        int min = 0, min_pos = 0;
        for(int r = k; r <= n; ++ r){
            if(S[r] >= min){
                tl = min_pos + 1;
                tr = r;
                return {true, tl, tr};
            }
            int j = r - k + 1;
            if(S[j] < min){
                min = S[j];
                min_pos = j;
            }
        }
        return {false, -1, -1};
    };

    int lo = 1, hi = n;
    while(lo < hi){
        int mid = (lo + hi + 1) >> 1;
        if (std::get<0>(check(mid))){
            lo = mid;
        } else {
            hi = mid - 1;
        }
    }
    int max = lo;
    auto [_, L, R] = check(max);

    std::cout << max << " " << L << " " << R << "\n";
}

int main() {
    std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    int t = 1;
    std::cin >> t;
    while (t -- ) {
        solve();
    }
    return 0;
}
posted @ 2025-07-28 00:36  maburb  阅读(783)  评论(2)    收藏  举报