1981(div2)
A. Turtle and Piggy Are Playing a Game
乌龟和小猪在玩数字游戏。
首先,小乌龟会选择一个整数
然后,小猪会一直进行下面的运算,直到
- 选择一个整数
,使得 和 (即 是 的倍数)。 - 将
设为 ,得分将增加 。
最初的得分是
void solve() {
int l, r;cin >> l >> r;
cout << __lg(r) << '\n';
}
B. Turtle and an Infinite Sequence
有一个无限长的序列
每过一秒,序列中的每个元素都会同时变化。每一个正整数
乌龟要找出
结果即为
void solve() {
int n, m;cin >> n >> m;
int l = max(n - m, 0), r = n + m;
if (!m) {
cout << n << '\n';return;
}
cout << (l | (1 << (__lg(l ^ r) + 1)) - 1) << '\n';
// int ans = 0;
// for (int i = 0;i <= 30;i++) {
// int a = l >> i;
// int b = r >> i;
// if (a & 1)ans |= 1 << i;
// if (a < b)ans |= 1 << i;
// }
// cout << ans << '\n';
}
C. Turtle and an Incomplete Sequence
补全
这个题目可以算是大模拟或者思维题。
jiangly 思路:
先将两边的
void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
if (count(a.begin(), a.end(), -1) == n) {
for (int i = 0; i < n; i++) {
a[i] = i % 2 + 1;
}
} else {
for (int i = 0, j = -1; i <= n; i++) {
if (i == n || a[i] != -1) {
if (j == -1) {
for (int k = i - 1; k >= 0; k--) {
a[k] = a[k + 1] == 1 ? 2 : a[k + 1] / 2;
}
} else if (i == n) {
for (int k = j + 1; k < n; k++) {
a[k] = a[k - 1] == 1 ? 2 : a[k - 1] / 2;
}
} else {
int l = j, r = i;
while (l + 1 < r) {
if (a[l] > a[r]) {
a[l + 1] = a[l] == 1 ? 2 : a[l] / 2;
l++;
} else {
a[r - 1] = a[r] == 1 ? 2 : a[r] / 2;
r--;
}
}
if (a[l] != a[r] / 2 && a[r] != a[l] / 2) {
cout << -1 << "\n";
return;
}
}
j = i;
}
}
}
for (int i = 0; i < n; i++) {
cout << a[i] << " \n"[i == n - 1];
}
}
官方题解 :
将每次变换看作完全二叉树上的移动,则可以看作最短路问题,
代码:
同样先把前后都填充了,然后对于每一个块,单独处理。
先计算出这个块两端的路线是怎样的。按照思路处理即可。
path 函数即在满二叉树上进行操作:
auto path = [](int x, int y)->vector<int> {
vector<int> l, r;
while (__lg(x) > __lg(y)) {
l.push_back(x);x >>= 1;
}
while (__lg(y) > __lg(x)) {
r.push_back(y);y >>= 1;
}
while (x != y) {
l.push_back(x);
r.push_back(y);
x >>= 1;y >>= 1;
}
l.push_back(x);
reverse(r.begin(), r.end());
for (auto x : r)l.push_back(x);
return l;
};
void solve() {
int n;cin >> n;
vector<int> a(n + 1), v;
int s = 0, e = 0;
for (int i = 1;i <= n;i++) {
cin >> a[i];
if (a[i] != -1) {
if (!s)s = i;
e = i;
v.push_back(i);
}
}
if (count(a.begin(), a.end(), -1) == n) {
for (int i = 1;i <= n;i++) {
cout << i % 2 + 1 << " \n"[i == n];
}
return;
}
for (int i = s - 1;i >= 1;i--) {
a[i] = (a[i + 1] == 1) ? 2 : a[i + 1] / 2;
}
for (int i = e + 1;i <= n;i++) {
a[i] = (a[i - 1] == 1) ? 2 : a[i - 1] / 2;
}
for (int i = 1;i < v.size();i++) {
int l = v[i - 1], r = v[i];
vector<int> p = path(a[l], a[r]);
if ((p.size() & 1) != ((r - l + 1) & 1) || r - l + 1 < p.size()) {
cout << "-1\n";return;
}
for (int j = 0;j < p.size();j++) {
a[l + j] = p[j];
}
for (int j = l + p.size(), o = 1;j <= r;j++, o ^= 1) {
a[j] = (o ? a[j - 1] * 2 : a[j - 1] / 2);
}
}
for (int i = 1;i <= n;i++) {
cout << a[i] << " \n"[i == n];
}
}
D. Turtle and Multiplication
给一个整数
- 对于所有
, 。 - 对于所有
, .
在所有这些序列中,小猪要求乌龟找出具有最少个不同元素的序列。
Solution
欧拉路径/Hierholzer 算法
需要学习欧拉图相关知识, 注:这个部分比较冷门
要使得
将
若完全图的点数为
-
若
为奇数,则每个点的度数都是偶数,则一定存在欧拉路径,路径则为边数 -
若
为偶数,则每个点的度数都为奇数,这个时候需要删除一些边至少保证有欧拉通路,最多只能剩下两个奇数度数的点,所以至少要删除 条边,路径长度为
若当
所以这时只需要确定最小的
对于最小的
代码:
void solve() {
int n;
cin >> n;
int m = 1;
while (n - 1 > (m % 2 == 1 ? m * (m + 1) / 2 : m * m / 2 + 1)) {
m++;
}
vector<int> a;
a.reserve(n);
vector<vector<int>> g(m, vector<int>(m, 1));
vector<int> cur(m);
if (m % 2 == 0) {
for (int i = 1; i < m - 1; i += 2) {
g[i][i + 1] = g[i + 1][i] = 0;
}
}
auto dfs = [&](auto&& self, int x) -> void {
for (int& i = cur[x]; i < m; i++) {
if (g[x][i]) {
g[x][i] = g[i][x] = 0;
self(self, i);
}
}
a.push_back(primes[x]);
};
dfs(dfs, 0);
a.resize(n);
for (int i = 0; i < n; i++) {
cout << a[i] << " \n"[i == n - 1];
}
}
这里需要用到筛法;
!模板整理
E. Turtle and Intersected Segments
乌龟刚刚收到了
乌龟将创建一个无向图
Turtle 希望你计算图
当且仅当
扫描线+最小生成树
(挖坑...)