牛客周赛 Round 102
A. 小红的好01串
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::cout << 2 << "\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. 小红的01串距离
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
std::vector<int> a;
for (int i = 0; i < n; ++ i) {
if (s[i] == '1') {
a.push_back(i);
}
}
if (a[1] - a[0] == a[2] - a[1]) {
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;
}
C. 小红的好01串修改
题意:给你一个\(01\)串,每次可以选择两个相邻位置将它们取反。要是的没有两个相邻位置的字符相同。求最少操作次数。
显然合法的串只有\(101010...\)和\(010101...\)两种。
那么分别和两个串计算一下,取最小值。
那么问题变成,我现在要把原串变成某个串\(t\),假设\([1, i - 1]\)都已经相等,而\(s_i \ne t_i\),那么我们只能操作\(i, i + 1\)这一对。于是从前往后扫一遍就行,最后判断是不是相等。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
if (n == 1) {
std::cout << 0 << "\n";
return;
}
auto check = [&](std::string s, std::string & t) -> int {
int res = 0;
for (int i = 0; i + 1 < n; ++ i) {
if (s[i] != t[i]) {
++ res;
s[i] ^= 1;
s[i + 1] ^= 1;
}
}
return s == t ? res : 1e9;
};
std::string t(n, '1');
for (int i = 0; i < n; i += 2) {
t[i] = '0';
}
int ans = check(s, t);
t = std::string(n, '1');
for (int i = 1; i < n; i += 2) {
t[i] = '0';
}
ans = std::min(ans, check(s, t));
std::cout << (ans < 1e9 ? ans : -1) << "\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. 小红的华撃串
题意:给你一个\(01\)串,你可以任意修改其中的字符。求\(01\)子串的个数加\(10\)子串的个数恰好是\(3\)个最小修改数。
考虑\(dp\),\(f[i][j][k]\)表示前\(i\)个有\(j\)个\(10\)和\(01\)子串,前一个是\(k\)的最小修改数。
转移就是直接枚举当前位选什么就行。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
const int inf = 1e9;
std::array<std::array<int, 2>, 4> f;
for (int i = 0; i < 4; ++ i) {
f[i].fill(inf);
}
for (int i = 0; i < 2; ++ i) {
f[0][i] = s[0] - '0' != i;
}
for (int i = 1; i < n; ++ i) {
std::array<std::array<int, 2>, 4> g{};
for (int j = 0; j < 4; ++ j) {
g[j].fill(inf);
}
for (int j = 0; j < 4; ++ j) {
for (int x = 0; x < 2; ++ x) {
for (int y = 0; y < 2; ++ y) {
int t = x != y;
if (j + t > 3) {
continue;
}
g[j + t][y] = std::min(g[j + t][y], f[j][x] + (y != s[i] - '0'));
}
}
}
f = g;
}
int ans = std::min(f[3][0], f[3][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;
}
E. 小红的01串(easy)
题意:求包含\(k\)个全一子串的\(01\)串的最小长度。
\(k\)比较小,考虑\(dp\)预处理。
长度为\(i\)的全一子串贡献为\(\frac{i\times(i+1)}{2}\),那么最长也就\(\sqrt{2e5}\),把所有的\(\frac{i\times(i+1)}{2}\)和\(i\)存下来。
然后记\(f[i]\)有\(i\)个全一子串的最小长度。那么有\(f[i] = \min(f[i - \frac{j\times(j+1)}{2}] + i + 1\),因为我们每个全一子串之间要用一个\(0\)隔开,所以有个加一。因为最开始的全一子串前面没有\(0\),我们可以使得\(f[0] = -1\)。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
std::vector<int> f;
void init(int n) {
const int inf = 1e9;
f.assign(n + 1, inf);
std::vector<std::pair<int, int>> a;
for (int i = 1; i * (i + 1) / 2 <= n; ++ i) {
a.emplace_back(i * (i + 1) / 2, i);
}
f[0] = -1;
for (int i = 1; i <= n; ++ i) {
for (auto & [x, y] : a) {
if (x > i) {
break;
}
f[i] = std::min(f[i], f[i - x] + y + 1);
}
}
}
void solve() {
int k;
std::cin >> k;
std::cout << f[k] << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
init(2e5);
std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
F. 小红的01串(hard)
题意:和\(E\)差不多,不够还需输出方案。
记录有个\(pre\),意味\(f[i]\)是从\(f[i - \frac{pre[i] \times (pre[i] + 1)}{2}]\)转移过来的。
然后就能构造了。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
std::vector<int> f, pre;
void init(int n) {
const int inf = 1e9;
f.assign(n + 1, inf);
pre.assign(n + 1, 0);
std::vector<std::pair<int, int>> a;
for (int i = 1; i * (i + 1) / 2 <= n; ++ i) {
a.emplace_back(i * (i + 1) / 2, i);
}
f[0] = -1;
for (int i = 1; i <= n; ++ i) {
for (auto & [x, y] : a) {
if (x > i) {
break;
}
if (f[i] > f[i - x] + y + 1) {
f[i] = f[i - x] + y + 1;
pre[i] = y;
}
}
}
}
void solve() {
int k;
std::cin >> k;
std::string s;
while (k) {
s += std::string(pre[k], '1') + "0";
k -= pre[k] * (pre[k] + 1) / 2;
}
s.pop_back();
std::cout << s << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
init(2e5);
std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
G. 小红的双排列查询
题意:一个数组,\(Q\)次询问,每次求\([l,r]\)是不是双排列。
如果这个区间满足条件,那么区间长度是偶数,且最大值不超过\(\frac{r-l+1}{2}\),且恰好有\(\frac{r-l+1}{2}\)个不同的出现了两次的数。
区间最大值可以用\(st\)表维护,求区间内有多少不同的出现两次的数,是个典题:采花。
我们把询问离线下来操作即可。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
template <class T>
struct ST {
const T inf = std::numeric_limits<T>::max();;
std::vector<std::vector<T>> min, max;
ST(const std::vector<T> & a) {
init(a);
}
void init(const std::vector<T> & a) {
int n = a.size();
int lg = std::__lg(n) + 1;
min.assign(n, std::vector<T>(lg + 1, inf));
max.assign(n, std::vector<T>(lg + 1, -inf));
for (int i = 0; i < n; ++ i) {
min[i][0] = max[i][0] = a[i];
}
for (int j = 1; j <= lg; ++ j) {
for (int i = 0; i + (1 << j - 1) < n; ++ i) {
min[i][j] = std::min(min[i][j - 1], min[i + (1 << j - 1)][j - 1]);
max[i][j] = std::max(max[i][j - 1], max[i + (1 << j - 1)][j - 1]);
}
}
}
std::pair<T, T> query(int l, int r) {
if (l > r) {
return {inf, -inf};
}
int lg = std::__lg(r - l + 1);
return {std::min(min[l][lg], min[r - (1 << lg) + 1][lg]), std::max(max[l][lg], max[r - (1 << lg) + 1][lg])};
}
};
template <class T>
struct Fenwick {
int n;
std::vector<T> tr;
Fenwick(int _n) {
init(_n);
}
void init(int _n) {
n = _n;
tr.assign(_n + 1, T{});
}
void add(int x, const T &v) {
for (int i = x; i <= n; i += i & -i) {
tr[i] = tr[i] + v;
}
}
T query(int x) {
T res{};
for (int i = x; i; i -= i & -i) {
res = res + tr[i];
}
return res;
}
T sum(int l, int r) {
return query(r) - query(l - 1);
}
};
void solve() {
int n, q;
std::cin >> n >> q;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
ST<int> st(a);
std::vector<std::vector<std::pair<int, int>>> Q(n + 1);
for (int i = 0; i < q; ++ i) {
int l, r;
std::cin >> l >> r;
Q[r].emplace_back(l, i);
}
std::vector<int> ans(q);
std::vector<int> last(n + 1), last1(n + 1);
Fenwick<int> tr(n + 1);
for (int r = 1; r <= n; ++ r) {
if (a[r] <= n) {
if (last1[a[r]]) {
tr.add(last1[a[r]], -1);
}
if (last[a[r]]) {
tr.add(last[a[r]], 1);
}
last1[a[r]] = last[a[r]];
last[a[r]] = r;
}
for (auto & [l, id] : Q[r]) {
if (r - l + 1 & 1) {
continue;
}
if (st.query(l, r).second > (r - l + 1) / 2) {
continue;
}
if (tr.sum(l, r) != (r - l + 1) / 2) {
continue;;
}
ans[id] = 1;
}
}
for (int i = 0; i < q; ++ i) {
std::cout << (ans[i] ? "Yes" : "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;
}