A. Too Min Too Max
贪心、排序。
对数组排序后,显然当下标 \(i\)、\(j\)、\(k\)、\(l\) 分别选择 \(1\)、\(n\)、\(2\)、\(n - 1\) 时求得最大值。
时间复杂度:\(O(nlogn)\) 。
#include <bits/stdc++.h>
using namespace std;
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()
using i64 = long long;
void solve() {
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
sort(ALL(a));
cout << 2 * (a[n] + a[n - 1] - a[1] - a[2]) << '\n';
}
void prework() {
}
int main() {
cctie;
prework();
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
B. Yet Another Coin Problem
枚举、贪心。
价值为 \(1\) 的硬币最多需要 \(2\) 个,当需要 \(3\) 个及以上时,可由 价值更高的硬币替代;以此类推,价值为 \(3\)、\(6\)、\(10\) 的硬币分别最多需要 \(1\)、\(5\)、\(3\) 个,然后剩余需要补齐的价值均由价值为 \(15\) 的硬币补齐。则通过分别枚举价值 \(1\)、\(3\)、\(6\)、\(10\) 的硬币数量在所有可行解中取最小值为答案。
#include <bits/stdc++.h>
using namespace std;
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()
using i64 = long long;
void solve() {
int n;
cin >> n;
int ans = n;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 6; k++) {
for (int l = 0; l < 3; l++) {
int x = n - i - j * 3 - k * 6 - l * 10;
if (x >= 0 && x % 15 == 0) {
ans = min(ans, i + j + k + l + x / 15);
}
}
}
}
}
cout << ans << '\n';
}
void prework() {
}
int main() {
cctie;
prework();
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
C. Find a Mine
数学。
随机选择一个点作为询问点时,距离询问点最近的雷可能存在的位置太多,不好在 \(4\) 次询问中确定一个雷的具体位置。而通过第一个样例的提示,我们发现当询问点为两条边界的交点时,可以得到距离最近的地雷可能的位置会在一条直线上,则我们的策略为选择三个这样的点(因为会受另一个地雷的干扰,仅选两个点是不够的),不妨选择 \((1, 1)\)、\((1, m)\)、\((n, 1)\) ,依次询问可得到三条直线,三条直线上点的坐标均可由二元一次方程表示,解方程组并判断合法性即可求得交点。画图可知,交点的数量可能为 \(1\) 或 \(2\) ,若为 \(1\) 时,显然交点即为所求点;若为 \(2\) 时,则第 \(4\) 次询问用于筛除其中一点。
时间复杂度:\(O(1)\) 。
#include <bits/stdc++.h>
using namespace std;
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()
using i64 = long long;
int ask(int x, int y) {
cout << "? " << x << " " << y << endl;
int d;
cin >> d;
return d;
}
void get(int x, int y) {
cout << "! " << x << " " << y << endl;
}
void solve() {
int n, m;
cin >> n >> m;
int d1 = ask(1, 1), d2 = ask(1, m), d3 = ask(n, 1);
int x1 = (d1 + d2 + 3 - m) / 2, y1 = x1 - (d2 - m + 1);
int y2 = (d1 + d3 + 3 - n) / 2, x2 = y2 - (d3 - n + 1);
auto is_legal = [&](int x, int y)->bool {
return 1 <= x && x <= n && 1 <= y && y <= m && x + y == 2 + d1;
};
if (is_legal(x1, y1)) {
if (is_legal(x2, y2)) {
int d = ask(x1, y1);
if (d) {
get(x2, y2);
} else {
get(x1, y1);
}
} else {
get(x1, y1);
}
} else {
get(x2, y2);
}
}
void prework() {
}
int main() {
cctie;
prework();
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
D1. XOR Break — Solo Version
位运算、分类讨论。
这里讨论一种最多只需要操作 2 次的做法。
当二进制数 \(n\) 包含 \(1\) 的个数为 \(1\) 时,显然对 \(n\) 已无法进行任何操作,因为选择任意一个比 \(n\) 小的数 \(y\) 来异或时,\(y\) 数位为 \(1\) 时 \(n\) 显然不为 \(1\),则 \(n \lt n \oplus y\) ;
当二进制数 \(n\) 包含多个 \(1\) 时,我们可以进行一种核心操作拆 \(1\) 补 \(1\) 的操作,比如 \(n = 101001\),我们可以选择 \(y = 001110\) 与 \(n\) 异或,得 \(1001111\) ,即拆了某个非最高位的 \(1\) 然后使该位之后的所有数位都为 \(1\) ,这是一种拆非最高位的操作,当然也可以拆最高位,刚刚的例子里,\(n\) 不变,我们可以选择 \(y = 100110\) 与 \(n\) 异或,得 \(001111\) ,即使得次高位及其之后的所有位为 \(1\) 。通过刚才的例子我们发现,我们没法在最高位和次高位的两个 \(1\) 之间进行任何拆补操作,所以当在这些位中 \(m\) 为 \(1\) 而 \(n\) 为 \(0\) 时,则无法实现转换,否则我们可以通过拆补来实现 \(n\) 到 \(m\) 的转换。
当 \(m\) 在 \(n\) 的最高位 \(1\) 的数位上为 \(0\) 时,我们则考虑拆最高位;当 \(m\) 在 \(n\) 的最高位 \(1\) 的数位上为 \(1\) 时,我们则考虑拆从高位往低位第一个出现的 \(n\) 为 \(1\) 且 \(m\) 为 \(0\) 的 \(1\);
拆补完后,可以一步转换成 \(m\),因为 \(n\) 在被拆的 \(1\) 的数位及其所有高位都与 \(m\) 相等,而其所有低位都已为 \(1\),对每一位 \(1\) 到 \(0\) 的转换是可以直接进行的(通过异或)。
#include <bits/stdc++.h>
using namespace std;
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()
using i64 = long long;
void solve() {
i64 n, m;
cin >> n >> m;
if (__builtin_popcountll(n) == 1) {
cout << -1 << '\n';
} else {
int h = 0, k = 0;
for (int i = 62; ~i; i--) {
int u = n >> i & 1, v = m >> i & 1;
if (u) {
if (!h) {
h = i;
}
if (!v) {
k = i;
break;
}
}
}
vector<i64> ans(1, n);
n -= 1LL << k;
if (h == k) {
int lh;
for (int i = h - 1; ~i; i--) {
int u = n >> i & 1, v = m >> i & 1;
if (v > u) {
cout << -1 << '\n';
return;
}
if (u) {
lh = i;
break;
}
}
k = lh;
}
for (int i = k - 1; ~i; i--) {
int u = n >> i & 1;
if (!u) {
n += 1LL << i;
}
}
ans.push_back(n);
if (n != m) {
ans.push_back(m);
}
cout << ans.size() - 1 << '\n';
for (i64 i : ans) {
cout << i << " \n"[i == m];
}
}
}
void prework() {
}
int main() {
cctie;
prework();
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
D2. XOR Break — Game Version
位运算、博弈论。
我们先分析 \(n\) 中 \(1\) 的个数 \(k\) 较少的情况:\(k = 1\) 时,无法操作,先手必败;\(k = 2\) 时,先手可以拆成两个 \(k = 1\) 的数,先手必胜,不难想到 先手胜负 与 \(k\) 的奇偶有关,不妨。
当 k 为偶数时,一定可以分解成两个 \(k\) 为奇数的数;
当 \(k\) 为奇数时,如果是直接将所有为 \(1\) 的数位任意的分到两个数中,则一定有一个数的 \(k\) 为偶数,一个为奇数;如果用了 \(D1\) 中的拆分操作,则有一些数位由原本的 \(0\) 变为 \(1\) 和 \(1\) 变为 \(0\),当有一个 \(0\) 变为 \(1\) 时,分解后的两个数的 \(k\) 的奇偶性同时改变,\(1\) 变为 \(0\) 也是如此,而分解后的两个数的 \(k\) 奇偶性总是互异的,所以得出分解后的两个数的 \(k\) 一奇一偶。
所以我们得到偶必得奇且奇能得偶,而 \(k = 1\) 时无法操作且游戏为有限轮( \(D1\) 中的拆分操作是有限次的),得出 \(k\) 为偶数先手必胜, \(k\) 为奇数先手必败的结论。
由于操作次数限制在不超过 \(63\) 次,为了避免拆分操作不断添加 \(1\) 的数量而延长操作次数,每到 \(Alice\) 操作时,我们就选择将 \(n\) 分解成 \(n\) 的最高位和 \(n\) 的剩余部分,这样可以保证每次能将 \(1\) 的上限数量减一,这样则能保证操作次数在限制内。
#include <bits/stdc++.h>
using namespace std;
#define cctie ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define all(x) x.begin(), x.end()
#define ALL(x) x.begin() + 1, x.end()
using i64 = long long;
void solve() {
i64 n;
cin >> n;
int turn;
if (__builtin_popcountll(n) & 1) {
cout << "second" << endl;
turn = 1;
} else {
cout << "first" << endl;
turn = 0;
}
i64 p1 = 1, p2 = 1;
while (p1 != 0 || p2 != 0) {
if (turn == 0) {
for (int i = 62; ~i; i--) {
int u = n >> i & 1;
if (u) {
p1 = 1LL << i;
break;
}
}
p2 = n ^ p1;
cout << p1 << " " << p2 << endl;
} else {
cin >> p1 >> p2;
if (p1 == -1 && p2 == -1) {
exit(0);
}
if (__builtin_popcountll(p1) % 2 == 0) {
n = p1;
} else {
n = p2;
}
}
turn ^= 1;
}
}
void prework() {
}
int main() {
cctie;
prework();
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}
标签:cout,int,cin,long,using,931,D2,Div,define
From: https://www.cnblogs.com/xiojoy/p/18042233