Codeforces Global Round 22 A-E
A
题解
知识点:贪心。
显然交错释放最好。
若两类数量不一样,那么较少的一组的一定都可以双倍,剩下的另一组就放进一个优先队列,从大到小和少的一组匹配可以双倍,剩下的直接加。
如果两类数量一样,那一定有一个不能被双倍。用上面的方法后,减去一个两组的最小值即可。
时间复杂度 \(O(n \log n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[100007], b[100007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
for (int i = 1;i <= n;i++) cin >> b[i];
int cnt1 = 0;
for (int i = 1;i <= n;i++) if (a[i]) cnt1++;
ll sum = 0;
bool typ = cnt1 <= n - cnt1;
int cnt = min(cnt1, n - cnt1);
priority_queue<int> pq;
for (int i = 1;i <= n;i++) {
if (a[i] == typ) sum += 2 * b[i];
else pq.push(b[i]);
}
for (int i = 1;i <= cnt;i++) {
sum += pq.top() * 2;
pq.pop();
}
while (pq.size()) {
sum += pq.top();
pq.pop();
}
if (n - cnt == cnt) sum -= *min_element(b + 1, b + n + 1);
cout << sum << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
B
题解
知识点:枚举,前缀和,贪心。
注意,给出的 \(k\) 个前缀和,能确定后 \(k-1\) 个数,其他数是可以自由分配的,那么现在只需要让倒数第 \(k\) 个数最小即可。
显然 \(a[n-k+1]\) 最小值为 \(\Bigg \lceil \dfrac{s[n-k+1]}{n-k+1} \Bigg \rceil\) ,即把 \(s[n-k+1]\) 的值平均分配给 \(n-k+1\) 个位置,就能保证 \(a[n-k+1]\) 最小。
接下来,通过这个最小的 \(a[n-k+1]\) 检验后面 \(k-1\) 项是否合法即可。
时间复杂度 \(O(k)\)
空间复杂度 \(O(k)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int s[100007];
bool solve() {
int n, k;
cin >> n >> k;
for (int i = 1;i <= k;i++) cin >> s[i];
int cur;
if (s[1] <= 0) cur = s[1] / (n - k + 1);
else cur = (s[1] + n - k) / (n - k + 1);
for (int i = 2;i <= k;i++) {
if (s[i] - s[i - 1] < cur) return false;
cur = s[i] - s[i - 1];
}
cout << "YES" << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << "NO" << '\n';
}
return 0;
}
C
题解
方法一
知识点:博弈论。
考虑奇数数量 \(cnt\) 模 \(4\) 的四种情况。
- \(cnt \equiv 0 \pmod 4\) ,此时A总是能拿到偶数个奇数,必赢。
- \(cnt \equiv 1 \pmod 4\) ,若 \(n\) 为偶数,那A可以不拿多出来的那个奇数,从而必赢;否则,一定会拿多一个奇数,必输。
- \(cnt \equiv 2 \pmod 4\) ,此时A总是能拿到奇数个奇数,必输。
- \(cnt \equiv 3 \pmod 4\) ,此时A总是能拿到偶数个奇数,必赢。
时间复杂度 \(O(n)\)
空间复杂度 \(O(1)\)
方法二
知识点:博弈论,线性dp,记忆化搜索。
设 \(dp[turn][st][cnt0][cnt1]\) 当前为A/B(0/1)的回合,A手里的奇偶性,偶数剩 \(cnt0\) ,奇数剩 \(cnt1\) 时当前回合人的输赢。终止局面:A的回合且A的和为偶数时为A赢,B的回合且A的和为奇数时为B赢,其他情况均为当前回合的人输。
这样每个回合,只要下一回合奇数偶数中有一种情况是下一个回合的人输,那自己一定是赢的,每次或转移即可。
还有种设法是只看 \(A\) 的输赢,但写起来不方便,因为上面这种写法可以同一或转移,这种写法A是或转移,B是且转移。因为B只要有一种能让A输就会走,应该是且,那就需要多一个判断回合。
时间复杂度 \(O(n^2)\)
空间复杂度 \(O(n^2)\)
代码
方法一
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool solve() {
int n;
cin >> n;
int cnt = 0;
for (int i = 1;i <= n;i++) {
int x;
cin >> x;
if (x & 1) cnt++;
}
if (cnt % 4 == 0 || cnt % 4 == 3) cout << "Alice" << '\n';
else if (cnt % 4 == 1) cout << (n & 1 ? "Bob" : "Alice") << '\n';
else if (cnt % 4 == 2) cout << "Bob" << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
方法二
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int dp[2][2][107][107];//A/B(0/1)的回合,A手里的奇偶性,偶数剩多少,奇数剩多少
bool dfs(bool turn, bool st, int cnt0, int cnt1) {
if (~dp[turn][st][cnt0][cnt1]) return dp[turn][st][cnt0][cnt1];
if (!cnt0 && !cnt1) return !st ^ turn;
bool ans = 0;
if (cnt0) ans |= !dfs(!turn, st, cnt0 - 1, cnt1);
if (cnt1) ans |= !dfs(!turn, st ^ !turn, cnt0, cnt1 - 1);
return dp[turn][st][cnt0][cnt1] = ans;
}
bool solve() {
memset(dp, -1, sizeof(dp));
int n;
cin >> n;
int cnt0 = 0, cnt1 = 0;
for (int i = 1;i <= n;i++) {
int x;
cin >> x;
if (x & 1) cnt1++;
else cnt0++;
}
cout << (dfs(0, 0, cnt0, cnt1) ? "Alice" : "Bob") << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
D
题解
知识点:构造。
首先解决 \(k\) 。注意到,\(i<b[i]\) 的情况只出现在 \(a[i] \leq k,a[j]>k(1\leq j<i)\) 的情况。而 \(a\) 是个排列,即每个数字出现且仅出现一次,因此 \(i<b[i]\) 的个数,说明 \(\leq k\) 的数有多少个,即 \(k\) 的大小。
随后处理排列顺序。观察题意可以得到, \((i,b[i]) = (a[x],a[y]),(1\leq y<x)\) 可以得到 \(b[i]\) 一定是 \(i\) 的前驱。
若多个数字的前驱相同,那么这些同前驱的数字只有其中一个可以作为其他数字的前驱,且在原排列 \(a\) 中一定出现在同前驱数字的最后,否则会互相干扰,因此不存在这样的 \(b\) 。
如果 \(b[i] = 0 \text{ 或 } n+1\) 时,代表 \(i\) 前面没有别的数字,不难发现 \(0\) 和 \(n+1\) 只会有且只有一种出现在 \(b\) 中。
因此,可以先用一个桶把 \(b[i]\) 相同的 \(i\) 存在一起,表示这些 \(i\) 的前驱相同。然后从 \(b[i] = 0 \text{ 或 } n+1\) 出发,先找到一个桶里有后继的数,把这个数放在桶的最后,再从头依次输出即可,接下来到最后一个数字,即有后继的数字,桶中重复上述操作即可。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int b[100007];
vector<int> v[100007];
bool solve() {
int n;
cin >> n;
v[0].clear();
v[n + 1].clear();
for (int i = 1;i <= n;i++) cin >> b[i], v[i].clear();
int k = 0;
for (int i = 1;i <= n;i++) if (i < b[i]) k++;
for (int i = 1;i <= n;i++) v[b[i]].push_back(i);
cout << k << '\n';
int cur = 0;
if (v[n + 1].size()) cur = n + 1;
int cnt = 0;
while (cnt < n) {
for (auto &i : v[cur]) {
if (v[i].size()) {
swap(i, v[cur].back());
break;
}
}
for (auto i : v[cur]) cout << i << ' ';
cnt += v[cur].size();
cur = v[cur].back();
}
cout << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
E
题解
知识点:排列组合,双指针。
可以放置隔板划分连续区间,考虑区间 \((i,j)\) 的三种情况:
- 全是 \(0\) ,形如
00000000,那么任意放置隔板都能产生回文,所以生成 \(2^{j-i}\) 种方案。 - 两侧都有 \(0\) 但中间两侧有数字挡着,形如
000数字..任意..数字0000,那么考虑处理出两侧隔板方案。设左右侧分别有 \(x,y\) 个 \(0\) ,且两侧需要放相同数量的隔板,因此方案数为 \(C_x^k \cdot C_y^k,k \in [0,\min{(x,y)}]\) 。 - 两侧至少有一侧没有 \(0\) ,形如
00数字..任意..数字,这时候没有 \(0\) 可以直接处理,那就要处理出从两侧出发和相同的一段。假设和相同时,左段右端点是 \(l\) ,右段左端点是 \(r\) ,若 \(l\geq r\) ,说明两端重合了不能形成回文;否则,可以把这一段整体等效 \(0\) ,参与下一次区间的处理。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 998244353;
int fact[100007], invf[100007];
int a[100007];
int qpow(int a, int k) {
int ans = 1;
while (k) {
if (k & 1) ans = 1LL * ans * a % mod;
k >>= 1;
a = 1LL * a * a % mod;
}
return ans;
}
void init(int n) {
fact[0] = 1;
for (int i = 1;i <= n;i++) fact[i] = 1LL * fact[i - 1] * i % mod;
invf[n] = qpow(fact[n], mod - 2);
for (int i = n;i >= 1;i--) invf[i - 1] = 1LL * invf[i] * i % mod;
}
int C(int n, int m) {
return 1LL * fact[n] * invf[m] % mod * invf[n - m] % mod;
}
int f(int i, int j) {
int l = i, r = j;
while (l <= j && !a[l]) l++;
while (r >= i && !a[r]) r--;
if (l == j + 1) return qpow(2, j - i);
if (l != i && r != j) {
int ans = 0, x = l - i, y = j - r;
for (int i = 0;i <= min(x, y);i++)
ans = (ans + 1LL * C(x, i) * C(y, i)) % mod;
return 1LL * ans * f(l, r) % mod;
}
ll ls = a[l], rs = a[r];
while (l < r && ls != rs) {
if (ls < rs) ls += a[++l];
else rs += a[--r];
}
if (l >= r) return 1;
a[l] = a[r] = 0;
return f(l, r);
}
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
cout << f(1, n) << '\n';
return true;
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
init(100001);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}
Codeforces Global Round 22 A-E的更多相关文章
- [题解] Codeforces Global Round 22 1738 A B C D E F 题解
很久没rated打过cf的比赛了,这次打得还行,至少进前100了 点我看题 A. Glory Addicts 把类型0的数放进数组a里,类型1的数放进数组b里.如果\(|a|=|b|\),你可以把所有 ...
- CodeForces Global Round 1
CodeForces Global Round 1 CF新的比赛呢(虽然没啥区别)!这种报名的人多的比赛涨分是真的快.... 所以就写下题解吧. A. Parity 太简单了,随便模拟一下就完了. B ...
- Codeforces Global Round 1 - D. Jongmah(动态规划)
Problem Codeforces Global Round 1 - D. Jongmah Time Limit: 3000 mSec Problem Description Input Out ...
- Codeforces Beta Round #22 (Div. 2 Only)
Codeforces Beta Round #22 (Div. 2 Only) http://codeforces.com/contest/22 A 水题 #include<bits/stdc+ ...
- Codeforces Global Round 2 题解
Codeforces Global Round 2 题目链接:https://codeforces.com/contest/1119 A. Ilya and a Colorful Walk 题意: 给 ...
- Codeforces Global Round 1 (A-E题解)
Codeforces Global Round 1 题目链接:https://codeforces.com/contest/1110 A. Parity 题意: 给出{ak},b,k,判断a1*b^( ...
- 暴力/DP Codeforces Beta Round #22 (Div. 2 Only) B. Bargaining Table
题目传送门 /* 题意:求最大矩形(全0)的面积 暴力/dp:每对一个0查看它左下的最大矩形面积,更新ans 注意:是字符串,没用空格,好事多磨,WA了多少次才发现:( 详细解释:http://www ...
- Codeforces Global Round 3
Codeforces Global Round 3 A. Another One Bites The Dust 有若干个a,有若干个b,有若干个ab.你现在要把这些串拼成一个串,使得任意两个相邻的位置 ...
- Codeforces Global Round 1 (CF1110) (未完结,只有 A-F)
Codeforces Global Round 1 (CF1110) 继续补题.因为看见同学打了这场,而且涨分还不错,所以觉得这套题目可能会比较有意思. 因为下午要开学了,所以恐怕暂时不能把这套题目补 ...
- 【手抖康复训练1 】Codeforces Global Round 6
[手抖康复训练1 ]Codeforces Global Round 6 总结:不想复习随意打的一场,比赛开始就是熟悉的N分钟进不去时间,2333,太久没写题的后果就是:A 题手抖过不了样例 B题秒出思 ...
随机推荐
- VUEX 使用学习六 : modules
转载请注明出处: 当Store中存放了非常多非常大的共享数据对象时,应用会变的非常的复杂,Store对象也会非常臃肿,所以Vuex提供了一个Module模块来分隔Store.通过对Vuex中的Stor ...
- Java求一个集合的所有子集
转载请注明出处: 求一个集合的所有子集表示从一个集合当中,任取任意项或不取,所能得到的所有结果,比如有一个集合{a,b,c,d},那么{a,b}, {b, d}等都是它的子集,空集也是它的子集, 一个 ...
- c#(nanoframework)安装单片机环境;如何使用c#写类似于c的单片机驱动
.NET nanoFramework 安装教程 准备材料 esp32单片机(支持wifi蓝牙) 安卓数据线(需要支持传输) 注意!请先安装esp32驱动程序 ESP32驱动链接 安装 .NET n ...
- [转帖]资料整理——Oracle版本历史(很全面)(Releases and versions of Oracle Database)
资料来源: https://en.wikipedia.org/wiki/Oracle_Database Oracle Database Version Initial Release Version ...
- [转帖]Linux内核参数 rp_filter
https://www.cnblogs.com/chenmh/p/6001977.html 简介 rp_filter (Reverse Path Filtering)参数定义了网卡对接收到的数据包进行 ...
- 【转帖】50.设置HotSpot采用解释器还是JIT编译器(-Xint、-Xcomp、Xmixed以及-Server、-Client)
目录 1.设置HotSpot 1.设置HotSpot 1.设置采用解释器还是JIT编译器 -Xint: 完全采用解释器模式执行程序. -Xcomp: 完全采用即时编译器模式执行程序.如果即时编译出现问 ...
- [转帖]基本系统调用性能lmbench测试方法和下载
简介 Lmbench是一套简易,可移植的,符合ANSI/C标准为UNIX/POSIX而制定的微型测评工具.一般来说,它衡量两个关键特征:反应时间和带宽. Lmbench旨在使系统开发者深入了解关键操作 ...
- [转帖]gcc -O0 -O1 -O2 -O3 四级优化选项及每级分别做什么优化
相关博客http://blog.chinaunix.net/uid-24954950-id-2956476.html 相关博客http://blog.csdn.net/misiter/article/ ...
- 将自签名创建的ca证书 添加到linux的授信证书列表的办法
第一步: 将ca 证书 从cert 格式转换成pem格式 openssl x509 -in ca.crt -out ca.pem -outform PE 第二步: 将ca 证书导入至系统中来 cat ...
- 拜占庭将军问题和 Raft 共识算法讲解
作者: 京东物流 郭益如 导读 在分布式系统中, 什么是拜占庭将军问题?产生的场景和解决方案是什么?什么是 Raft 共识算法?Raft 算法是如何解决拜占庭将军问题的?其核心原理和算法逻辑是什么?除 ...