VP Educational Codeforces Round 77 (Rated for Div. 2)


A. Heating

题意:最多选\(n\)个非负整数,使得它们的和为\(m\),花费为每个数的平方之和。求最小花费。

应该让每个数都尽量接近。那么每个数至少为\(\lfloor \frac{m}{n} \rfloor\),有\(m\% n\)个数需要加一。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    i64 t = m / n;
    i64 ans = t * t * (n - m % n) + (t + 1) * (t + 1) * (m % n);
    std::cout << ans << "\n";
}

B. Obtain Two Zeroes

题意:给你两个数\(a, b\),你每次选择一个\(x\),使得一个减去\(x\),一个减去\(2x\)。求能不能使得它们都变成零。

发现总共减去\(3x\),那么\(a+b\)应该是\(3\)的倍数。同时\(b \leq 2a\)。这样才能在减完。

点击查看代码
void solve() {
    int a, b;
    std::cin >> a >> b;
    if (a > b) {
    	std::swap(a, b);
    }

    if ((a + b) % 3 == 0 && 2 * a >= b) {
    	std::cout << "YES\n";
    } else {
    	std::cout << "NO\n";
    }
}

C. Infinite Fence

题意:一个数轴,给\(r\)的倍数染红色,\(b\)的倍数染蓝书,\(r, b\)公倍数随便染。然后把染色的点拿出来排成一列。能不能使得没有一个连续长度大于等于\(k\)的相同颜色段。

\(r < b\)
那么\([kb + 1, (k + 1)b - 1]\)之间最多放\(\lfloor \frac{(k+1)b - kb - 2)}{r} \rfloor\)个红色点。但直接判断是错的,因为想要放满需要满足从\(kb + 2\)开始放,如何判断呢,其实就是\(rx + by = 1\)。显然需要\(r, b\)互质才能满足,那么就把\(r, b\)除以最大公约数就行。

点击查看代码
void solve() {
    i64 r, b, k;
    std::cin >> r >> b >> k;
    if (r > b) {
    	std::swap(r, b);
    }

    i64 d = std::gcd(r, b);
    r /= d, b /= d;

    if ((b - 2) / r + 1 < k) {
    	std::cout << "OBEY\n";
    } else {
    	std::cout << "REBEL\n";
    }
}

D. A Game with Traps

题意:\(m\)个队员,每个有\(a_i\)敏捷。路径长度为\(n\),一开始你在\(0\)点,有\(k\)个陷阱,每个陷阱布置在\([l_i, r_i]\),有\(d_i\)的危险度,如果\(a_i < d_i\),那么这名队员不能进入。你可以走到\(r_i\)摧毁这个陷阱。每次有两种移动选择,你一个人往左或往右一格,或者你和队员在同一个可以带他们一起移动。求在\(t\)时刻内你最多带几个队员到达\(n+1\)

考虑二分,我们肯定带前\(x\)\(a_i\)最大的。那么能带队员走就走,不能走取决于\(a_i\)最小的那个,那么我们需要把这些陷阱摧毁,走到\(r_i\)的过程中可能会遇到新的陷阱有更大的\(r_i\),此时应该一鼓作气走完把这些陷阱摧毁,然后回来接队员。

点击查看代码
void solve() {
    int m, n, k, t;
    std::cin >> m >> n >> k >> t;
    std::vector<int> a(m + 1);
    for (int i = 1; i <= m; ++ i) {
    	std::cin >> a[i];
    }
    a[0] = 1e9;

    std::ranges::sort(a, std::greater<>());
    std::vector<std::vector<std::pair<int, int>>> R(n + 1);
    for (int i = 0; i < k; ++ i) {
    	int l, r, d;
    	std::cin >> l >> r >> d;
    	R[l].emplace_back(r, d);
    }

    auto check = [&](int x) -> bool {
    	int sum = 0;
    	int r = 0, last = 0;
    	for (int i = 1; i <= n; ++ i) {
    		for (auto & [j, v] : R[i]) {
    			if (v > x) {
    				r = std::max(r, j);
    			}
    		}

			++ sum;
    		if (i == r) {
    			sum += (r - last) * 2;
    			last = i;
    		} else if (i > r) {
    			last = i;
    		}
    	}
    	sum += n + 1 - last;
    	return sum <= t;
    };

    int l = 0, r = m;
    while (l < r) {
    	int mid = l + r + 1 >> 1;
    	if (check(a[mid])) {
    		l = mid;
    	} else {
    		r = mid - 1;
    	}
    }

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

E. Tournament

题意:\(n\)个人,\(n\)\(2\)的幂。两两打比赛,第\(i\)个人能力为\(i\),两个人比赛能力打的人赢。你的朋友也参加了比赛,你想让他成为最后的赢家。你可以花费\(a_i\)贿赂第\(i\)个人,他就会和你朋友比赛时输掉比赛。你可以随意安排每一场谁和谁打。求最少花费多少贿赂。

如果朋友不是第\(n\)个人,那么必须贿赂第\(n\)个人。如果朋友在\([n / 2 + 1, n - 1]\)这一段,模拟发现最后可以只剩下朋友和第\(i\)个人。否则如果朋友在\([n / 4 + 1, n / 2]\),那么还要贿赂一个人。同理对于每个\(2\)的幂的一段,如果朋友还在前面,就需要贿赂一个。应该贿赂最便宜的。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    std::priority_queue<int, std::vector<int>, std::greater<>> heap;
    i64 ans = 0;
    auto lowbit = [&](int x) -> int {
    	return x & -x;
    };

    for (int i = n - 1; i >= 0; -- i) {
    	if (a[i] == -1) {
    		break;
    	}
    	heap.push(a[i]);
    	if (lowbit(i + 1) == i + 1) {
    		ans += heap.top();
    		heap.pop();
    	}
    }
    std::cout << ans << "\n";
}
posted @ 2025-05-05 17:38  maburb  阅读(12)  评论(0)    收藏  举报