Codeforces Round 1030 (Div. 2)


A. Equal Subsequences

题意:构造一个长度为\(n\)的恰好有\(k\)\(1\)\(01\)串,使得\(101, 010\)作为子序列出现的次数相等。

如果把\(0\)\(1\)分边放在两边,那么不会有任何的\(101, 010\)这样的子序列。

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

using i64 = long long;

void solve() {
	int n, k;
	std::cin >> n >> k;
	std::cout << std::string(k, '1') + std::string(n - k, '0') << "\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. Make It Permutation

题意:给你一个\(n\times n\)的矩阵,每行一开始都是\({1, 2, ... , n}\)。你每次可以选择某一行将其一个子区间翻转。最多操作\(2n\)次。求每一列都是排列的操作方案。

被这题卡了半天。。。
需要思维或者找规律的能力。
我们先给\([2, n]\)行翻转\([1, i]\),然后给\([1, n - 1]\)翻转\([i + 1, n]\)

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

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::vector<std::tuple<int, int, int>> ans;
	for (int i = 2; i <= n; ++ i) {
		ans.emplace_back(i, 1, i);
	}

	for (int i = 1; i < n; ++ i) {
		ans.emplace_back(i, i + 1, n);
	}

	std::cout << ans.size() << "\n";
	for (auto & [i, l, r] : ans) {
		std::cout << i << " " << 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;
}

C. Make It Beautiful

题意:给你一个数组,数组的价值定义为每个数的二进制表示下的\(1\)的个数的总和。你可以操作\(k\)次,每次把一个数加一。求最大价值。

一个数使得它的\(1\)个数加一最少加多少?这个数肯定一直加到一个若干个连续最低为都是\(1\)的数。那么枚举低位有多少\(1\),高位不变,若干大于这个数就是第一个使得这个数价值加一的数。
那么可以用小根堆维护一个加一需要的操作数和操作后变成的数。每次取最少操作数出来操作,直到操作数用完。

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

using i64 = long long;

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

    using PII = std::pair<i64, i64>;
    auto get = [&](i64 x) -> PII {
        for (i64 i = 0, y = 0;i < 62; ++ i) {
            y += 1ll << i;
            if ((x & ~y) + (2ll << i) - 1 > x) {
                return {(x & ~y) + (2ll << i) - 1 - x, 
                        (x & ~y) + (2ll << i) - 1};
            }
        }
        return {1e18, 0};
    };

    i64 ans = 0;
    std::priority_queue<PII, std::vector<PII>, std::greater<PII>> heap;
    for (int i = 0; i < n; ++ i) {
        ans += __builtin_popcount(a[i]);
        heap.emplace(get(a[i]));
    }

    while (heap.size() && k >= heap.top().first) {
        auto [v, x] = heap.top(); heap.pop();
        k -= v;
        ans += 1;
        heap.emplace(get(x));
    }

    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;
}

D1. Red Light, Green Light (Easy version)

题意:一个很长的马路,有\(n\)个红绿灯。第\(i\)个红绿灯在\(t \% k == d[i]\)\(t\)时刻会是红灯,如果此时你恰好在这个位置就会掉头。\(q\)次询问,每次给定一个初始位置,你往右边走。求能不能走出这条马路。

观察到\(n, k\)都比较小,可以定义状态\(s[i][0/1][j]\)表示在\(i\)点方向为左/右,时刻模\(k\)等于\(j\)的状态。使用记忆化搜索可以通过。我这里用\(3\)表示这个点可以出去,\(2\)表示这个点不能出去。用\(1\)表示这个点在路径上,用\(0\)表示这个点未被访问。可以把状态映射为一个数,开个一维数组就可以跑了。

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

using i64 = long long;

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

    int S = n * 2 * k;
    std::vector<int> st(S, 0);

    auto get = [&](int i, int dir, int mod){
        return ((i * 2 + dir) * k + mod );
    };

    auto next = [&](int u) ->  int{
        int tmod = u % k;
        int tmp = u / k;
        int dir = tmp % 2;
        int i = tmp / 2; 

        int ndir = dir;
        if (tmod == d[i]) ndir = dir ^ 1;

        if (ndir == 1){
            if (i == n - 1){
                return -1;
            } else {
                i64 d = p[i + 1] - p[i];
                int nt = (tmod + int(d % k)) % k;
                return get(i + 1, ndir, nt);
            }
        } else {
            if (i == 0){
                return -1;
            } else {
                i64 d = p[i] - p[i-1];
                int nt = (tmod + int(d % k)) % k;
                return get(i - 1, ndir, nt);
            }
        }
    };

    std::vector<int> path;
    for (int u = 0; u < S; u++){
        if (st[u] != 0) continue;
        path.clear();
        int v = u;
        while (true){
            if (v == -1){
                for (int w : path) st[w] = 3;
                break;
            }
            if (st[v] == 3){
                for (int w : path) st[w] = 3;
                break;
            }
            if (st[v] == 2){
                for (int w : path) st[w] = 2;
                break;
            }
            if (st[v] == 1){
                for (int w : path) st[w] = 2;
                break;
            }
            st[v] = 1;
            path.push_back(v);
            int w = next(v);
            v = w;
        }
    }

    for (int i = 0; i < Q; ++ i){
        i64 start = a[i];
        if (start > p[n - 1]){
            std::cout << "YES\n";
            continue;
        }
        int j = int(std::lower_bound(p.begin(), p.end(), start) - p.begin());\
        i64 d = p[j] - start;
        int t0 = d % k;
        int u = get(j, 1, t0);
        if (st[u] == 3) std::cout << "YES\n";
        else std::cout << "NO\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-06-13 00:35  maburb  阅读(358)  评论(1)    收藏  举报