Codeforces Round #830 (Div. 2) A-D
A
题解
知识点:贪心,数论。
先求出序列最大公约数 \(d\) ,如果为 \(1\) 直接输出 \(0\) 。
否则,尝试用最后一个数操作, \(gcd(d,n) = 1\) 则可以,花费为 \(1\) 。
否则,用倒数第二个数操作,\(gcd(d,n-1) = 1\) (不必担心 \(n-1 = 0\) ,因为此时上一步一定成功),花费为 \(2\) 。
否则,用倒数两个数操作,一定成功,因为 \(gcd(n-1,n)=1\) ,花费为 \(3\) 。
时间复杂度 \(O(n \log n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[27];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
int d = a[1];
for (int i = 2;i <= n;i++) d = __gcd(a[i], d);
if (d == 1) cout << 0 << '\n';
else if (__gcd(d, n) == 1) cout << 1 << '\n';
else if (__gcd(d, n - 1) == 1) cout << 2 << '\n';
else cout << 3 << '\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
题解
知识点:贪心。
显然左侧已经排好的不用管,从第一段 \(1\) 开始记录后面一共分成的段数 \(cnt\)(如 0000|111|00|1|0|1|0 有 \(6\) 段)。若 \(cnt > 1\) ,则从第一段开始使用操作,每次可以将一段变为 \(0\) (后面也会改变),直到最后一段不用更改,一共操作 \(cnt-1\) 次。另外,如果 \(cnt = 0\) ,答案也是 \(0\) 。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool solve() {
int n;
cin >> n;
string s;
cin >> s;
s = "?" + s;
bool st = 0;
int cnt = 0;
for (int i = 1;i <= n;i++) {
if (s[i] != st + '0') {
cnt++;
st ^= 1;
}
}
cout << max(cnt - 1, 0) << '\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;
}
C
题解
知识点:枚举,双指针,位运算,前缀和,贪心。
因为异或相当于不进位的加法,那么前缀和减去前缀异或和一定是非减的,于是一个贪心的结论:最大值一定是 \(f(L_i,R_i)\) 的值。接下来需要用这个值,求一个最小区间。
为了方便区间运算,我们预处理一个前缀和,以及一个前缀异或和。
可以证明,最多删除 \(31\) 个非 \(0\) 元素,否则区间值必然减小。因为在 int 范围内, \(31\) 个二进制位,最多能分配给 \(31\) 个数一个不同为值的 \(1\) ,这样能使这 \(31\) 个数对答案没有贡献,实际情况不会超过 \(31\) ,因此我们放心大胆的枚举端点就行了。我们只需要考虑非 \(0\) 点,遍历一遍存一下非 \(0\) 点坐标即可。左端点从左往右,内循环右端点从右往左,区间等于最大值的如果长度更小就更新答案。
另外,需要特判没有非 \(0\) 元素的情况,此时直接输出 \(L,L\) 即可。
时间复杂度 \(O(n+q\log n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[100007];
ll sum[100007], sumx[100007];
bool solve() {
int n, q;
cin >> n >> q;
for (int i = 1;i <= n;i++) cin >> a[i];
vector<int> pos;
for (int i = 1;i <= n;i++) {
sum[i] = sum[i - 1] + a[i];
sumx[i] = sumx[i - 1] ^ a[i];
if (a[i]) pos.push_back(i);
}
while (q--) {
int L, R;
cin >> L >> R;
int l = lower_bound(pos.begin(), pos.end(), L) - pos.begin();
int r = upper_bound(pos.begin(), pos.end(), R) - pos.begin() - 1;
auto get = [&](int _l, int _r) {return sum[_r] - sum[_l - 1] - (sumx[_r] ^ sumx[_l - 1]);};
ll val = get(L, R);
int ansl = 0, ansr = n + 1;
for (int i = l;i <= r;i++) {
if (get(pos[i], pos[r]) < val) break;//可以证明无论左右端点至多删除31个非0元素对答案没有影响(0,2,4,8,...鸽巢原理)
for (int j = r;j >= i;j--) {
if (get(pos[i], pos[j]) < val) break;
if (pos[j] - pos[i] + 1 < ansr - ansl + 1) {
ansl = pos[i];
ansr = pos[j];
}
}
}
if (ansr - ansl + 1 > n) cout << L << ' ' << L << '\n';
else cout << ansl << ' ' << ansr << '\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;
}
D1
题解
知识点:STL,枚举。
用一个 set<ll> vis 维护出现过的元素,再用一个 map<ll,ll> last 维护某个元素上一次的询问结果,下一次询问这个元素时直接从上一次结果开始。
每个元素 \(i\) 只经过其倍数一次,共 \(\dfrac{n}{i}\) 次。所有元素次数之和 \(O(\sum \dfrac{n}{i}) = O(n \log n)\) 。
时间复杂度 \(O(q \log^2 q)\)
空间复杂度 \(O(q)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int q;
cin >> q;
set<ll> vis;
map<ll, ll> last;
while (q--) {
char op;
ll x;
cin >> op >> x;
if (op == '+') {
vis.insert(x);
}
else {
if (!last.count(x)) last[x] = x;
while (vis.count(last[x])) last[x] += x;
cout << last[x] << '\n';
}
}
return 0;
}
D2
题解
知识点:STL,枚举。
因为存在删除已存在元素的操作,这意味着我们之前得到的答案在未来可能不适用。
因此需要对每个已询问过的数字维护一个已删除集合 map<ll,set<ll>> del ,来得到目前某个元素的最大询问结果之前,是否有在序列中被删除的倍数。
对于已删除集合的维护,需要对每个询问过程中遍历到的且存在于序列中的倍数维护一个影响列表 map<ll,vector<ll>> chg ,来得到修改序列某个元素的状态时,哪些询问过的元素的已删除集合会被修改。
如此我们就维护了带删除求 mex 的数据结构。
时间复杂度 \(O(q \log ^2 q)\)
空间复杂度 \(O(q\log q)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int q;
cin >> q;
set<ll> vis;//序列中存在的元素
map<ll, ll> last;//某元素最大询问结果:记录需要维护的数据上界,超出最大询问结果的不需要考虑
map<ll, set<ll>> del;//某元素的已删除集合:最大询问结果内,目前不存在于序列中的倍数
map<ll, vector<ll>> chg;//某元素的影响列表:更改序列中某元素状态,已删除集合将发生变化的元素列表
while (q--) {
char op;
ll x;
cin >> op >> x;
if (op == '+') {
vis.insert(x);
for (auto y : chg[x]) del[y].erase(x);//删除受x影响元素的已删除集合中的x,因为x已存在
}
else if (op == '-') {
vis.erase(x);
for (auto y : chg[x]) del[y].insert(x);//增加受x影响元素的已删除集合中的x,因为x已删除
}
else {
if (!last.count(x)) last[x] = x;//新增已询问元素
if (del[x].size()) cout << *del[x].begin() << '\n';//已删除集合存在元素,优先使用
else {//考虑最大询问结果是否可行,否则扩大最大询问结果
while (vis.count(last[x])) {
chg[last[x]].push_back(x);//已存在的x的倍数,在未来可能会被修改状态,影响x的结果
last[x] += x;
}
cout << last[x] << '\n';
}
}
}
return 0;
}
Codeforces Round #830 (Div. 2) A-D的更多相关文章
- Codeforces Round #830 (Div. 2)D2. Balance (Hard version)(数据结构)
题目链接 题目大意 维护一个集合的mex,每次有三种操作: '+' x:将数 x 插入集合中 '-' x:将数 x 移除集合 '?' k:询问满足mex的数是k的倍数 既集合中未出现的数中最小的数可以 ...
- Codeforces Round #366 (Div. 2) ABC
Codeforces Round #366 (Div. 2) A I hate that I love that I hate it水题 #I hate that I love that I hate ...
- Codeforces Round #354 (Div. 2) ABCD
Codeforces Round #354 (Div. 2) Problems # Name A Nicholas and Permutation standard input/out ...
- Codeforces Round #368 (Div. 2)
直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...
- cf之路,1,Codeforces Round #345 (Div. 2)
cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅..... ...
- Codeforces Round #279 (Div. 2) ABCDE
Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems # Name A Team Olympiad standard input/outpu ...
- Codeforces Round #262 (Div. 2) 1003
Codeforces Round #262 (Div. 2) 1003 C. Present time limit per test 2 seconds memory limit per test 2 ...
- Codeforces Round #262 (Div. 2) 1004
Codeforces Round #262 (Div. 2) 1004 D. Little Victor and Set time limit per test 1 second memory lim ...
- Codeforces Round #371 (Div. 1)
A: 题目大意: 在一个multiset中要求支持3种操作: 1.增加一个数 2.删去一个数 3.给出一个01序列,问multiset中有多少这样的数,把它的十进制表示中的奇数改成1,偶数改成0后和给 ...
随机推荐
- 都说Dapper性能好,突然就遇到个坑,还是个性能问题
本来闲来无事,准备看看Dapper扩展的源码学习学习其中的编程思想,同时整理一个自己代码的单元测试,为以后的进一步改进打下基础. 突然就发现问题了,源码也不看了,改了好久. 测试Dapper.Lite ...
- LuoguP2575 高手过招(博弈论)
空格数变吗?不变呀 阶梯博弈阶梯数变吗?不变呀 那这不就阶梯博弈,每行一栋楼,爬完\(mex\)就可以了吗? #include <iostream> #include <cstdio ...
- Canvas 线性图形(三):曲线
前言 画曲线要用到二次贝塞尔曲线或三次贝塞尔曲线.贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如 PhotoShop. 二次贝塞尔曲线 二次贝塞尔曲线在 ...
- Java 断点下载(下载续传)服务端及客户端(Android)代码
原文: Java 断点下载(下载续传)服务端及客户端(Android)代码 - Stars-One的杂货小窝 最近在研究断点下载(下载续传)的功能,此功能需要服务端和客户端进行对接编写,本篇也是记录一 ...
- docker hung住问题排查
背景:这个是之前遇到的老问题. # systemctl status lxcfs● lxcfs.service - FUSE filesystem for LXC Loaded: loaded (/u ...
- 给你的博客加个aplayer
1.在 layout.ejs 中 body 标签内粘贴入以下 <!--音乐--> <link rel="stylesheet" href="https: ...
- LOJ6077「2017 山东一轮集训 Day7」逆序对 (生成函数+多项式exp?朴素DP!)
题面 给定 n , k n,k n,k ,求长度为 n n n 逆序对个数为 k k k 的排列个数,对 1 e 9 + 7 \rm1e9+7 1e9+7 取模. 1 ≤ n , k ≤ 100 ...
- 【c#】仅1600行代码 2D魔方游戏源码-纯WinForm
想起以前高三的时候写过一个很无脑的程序,那个时候.net5.0都还没影儿呢,,现在分享一下.一个平面展开的魔方游戏. 这个是1.0版本,有些许bug. 比如左边的格子操作不了. 「2d cube.ex ...
- DES|3DES|AES|RSA|DH | CA | SSL(HTTPS)
1.对称密钥算法: 加解密速度块,算法使安全的,已知算法无法推出密钥.但是密钥的分发困难. DES:对称密钥算法,是一种块加密算法,只有一个密钥.加解密都是用一个密钥. 3DES:与DES一样,可以认 ...
- 第六篇:vue.js模板语法(,属性,指令,参数)
Vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统. 结合响应系统,在应用状态改变时, Vue 能够智能地计算出重新渲染组件的最小代价并应用到 DOM 操作上.( ...