牛客周赛 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;
}
posted @ 2025-07-27 21:00  maburb  阅读(114)  评论(1)    收藏  举报