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