【CF】Day45——Codeforces Round 1021 (Div. 2) BC
阅读理解。。。不过挺有意思(
B. Sasha and the Apartment Purchase
题目:
思路:
看了半天没看懂...
题目叽里咕噜一大堆,说白了就是让我们在一个 可删除k个数 的 数组 中选 一些点 且 这些点的f(x) 是此时 删完了k个数之后的数组 中 所有可能的 f(x) 中最小的
可能还是有点不好懂,我们拿样例举例
3 1
6 7 9
由于我们最多只能删 1 个数,那么就有以下几种情况
6 7 9 / 6 9 / 6 7 / 7 9
那么要使得选的位置 x 是此时 f(x) 最小的,选法就是
选 7 / 选 6 7 8 9 / 选 6 7 / 选 7 8 9
那么最后就是 6 7 8 9 是可选的,所以答案就是 4
那么观察完样例之后,其实就有一点想法了,直接说结论吧
这题就是考中位数定理
这题其实就是这个应用部分,那么做法显而易见了
我们先排好序,然后可以枚举所有可能的数组,接着算出中位数的区间即可,但是如果枚举所有的可能是很慢的,经过观察,我们可以发现最后的情况就是:删除左边k个数得到剩余数的中位数(区间的右值) - 删除右边k个数得到剩余数的中位数(区间的左值)
所以结果就是 a[(n+k) / 2] - a[(n - k) / 2] + 1
特别的,由于我们的左值是要中位数的左边,所以最后其实是 a[(n+k) / 2] - a[(n - k - 1) / 2] + 1
比如6 2 / 5 1 9 10 13 2,操作就是
排序:1 2 5 9 10 13
右值:5 9 10 13,中位数就是 9 10 的右值,即 10
左值:1 2 5 9,中位数就是 9 10 的左值,即 2
结果就是 10 - 2 + 1 = 8,刚好对上样例
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "YES\n"
#define no cout << "NO\n"void solve()
{int n, k;cin >> n >> k;vector<int> a(n);for (int i = 0; i < n; i++){cin >> a[i];}sort(a.begin(), a.end());cout << a[(n+k) / 2] - a[(n-k - 1) / 2] + 1 << "\n";
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}
C. Sports Betting
题目:
思路:
很有意思,找规律
一个显然的答案就是如果对于同一天如果有4次打赌,那么肯定是可以的(2*2=4种情况)
否则我们来看看怎么构造一种方法来确保能赢
观察到样例 2 2 3 4 4这种情况是可以的,那是怎么赢的呢?(其实解决这个我们就写出来了)
对于由于 2 有两个,那么我们有两次机会猜 3 4,首先我们肯定是猜不中的(条件说要至少,往坏处想),那我们怎么猜才对我们最有利呢?一个想法就是我们猜 01 和 10
这样的话 3 起码会对一个(因为 3 要不就是0,要不就是1)
那么接下来讨论:
首先我们已经知道 3 是什么了,我们假设是 0,那么说明 01 猜对了一半,为什么是一半呢?因为条件说至少,所以我们不可能一次猜对。
那么也就是说 4 不可能是 1!也就说明 4 只能是 0
也就是说我们现在已经知道 4 的结果了,如果此时 3 有两次机会的话,我们就能猜 4 5 为 01 00,这一定能猜对的,因为 4 只能是 0,那么结果就压缩到两种可能了
但是这个例子中 3 只有一个,那怎么办呢?
还是和一样的结论,我们已经知道了 4 是 0,那么我们只需要猜 5 即可,我们可以猜 5 为 0 或 1,反正我们不可能一次猜对,也就相当于排除一个错误答案了,同时我们只有两个选择,那不就相当于我们知道了正确答案吗?只不过我们没选到罢了
所以现在我们就知道 5 是什么了,那么到 4 的时候我们要猜 5 6,由于 4 有两次机会,且 5 已经知道了,那么现在肯定是能猜中的。
那么如果 4 也只有一次呢?还是一样的操作,由于我们知道了 5,那我们就可以知道 6 的正确值了,以此类推....
自此我们讨论完毕,总结一下就是以下两种情况才有可能猜对:
①.某一天有4次机会猜,那么毋庸置疑可以猜对
②.对于连续的 k 天,如果机会数是 2 1 1 ... 1 1 2 这样的,那么也是可以猜对的
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "YES\n"
#define no cout << "NO\n"void solve()
{int n;cin >> n;vector<int> a(n);map<int, int> mp;for (int i = 0; i < n; i++){cin >> a[i];mp[a[i]]++;}for (auto x : mp){if (x.second >= 4){yes;return;}if (x.second >= 2 && mp[x.first + 1] >= 2){yes;return;}if (x.second >= 2){int add = 1;while (mp[x.first + add]){if (mp[x.first + add] >= 2){yes;return;}add++;}}}no;
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}