比赛链接

A

题解

知识点:贪心。

考虑两种方法:

  1. 所有不同的位置使用操作1变成相同
  2. 使用操作1将两串01数量相同,然后使用1次操作2

取其中最小的即可。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; int a[107], b[107];
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;
int cnt2 = 0;
for (int i = 1;i <= n;i++) {
cnt1 += a[i] != b[i];
cnt2 += a[i] - b[i];
}
cout << min(cnt1, abs(cnt2) + 1) << '\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

题解

知识点:数论,贪心。

充要条件:存在 \(b\) ,当且仅当 \(gcd(a[i-1],a[i+1]) | a[i]\) 。

显然,如果存在 \(b\) 那么 \(b[i]\) 一定会包括 \(a[i-1]\) 和 \(a[i]\) 的因子,而 \(a[i] = gcd(b[i],b[i+1])\) 一定能被 \(gcd(a[i-1],a[i])\) 整除。

若 \(gcd(a[i-1],a[i+1]) | a[i]\) ,那么构造 \(b[i] = lcm(a[i],a[i-1])\) ,则:

\[\begin{aligned}
gcd(b[i],b[i+1]) &= gcd(lcm(a[i-1],a[i]),lcm(a[i],a[i+1])) \\
&= a[i] \cdot gcd\bigg(\frac{a[i-1]}{gcd(a[i-1],a[i])},\frac{a[i+1]}{gcd(a[i],a[i+1])}\bigg)
\end{aligned}
\]

注意到,因为 \(gcd(a[i-1],a[i+1])|a[i]\) ,因此 \(gcd(a[i-1],a[i])\) 一定包含 \(gcd(a[i-1],a[i+1])\) ,同理 \(gcd(a[i],a[i+1])\) 也是,因此 \(gcd\bigg(\dfrac{a[i-1]}{gcd(a[i-1],a[i])},\dfrac{a[i+1]}{gcd(a[i],a[i+1])}\bigg) = 1\) ,所以 \(gcd(b[i],b[i+1]) = a[i]\) ,存在 \(b\) 。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; int a[100007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
for (int i = 2;i <= n - 1;i++) {
if (a[i] % __gcd(a[i - 1], a[i + 1])) return false;
}
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;
}

C1

题解

知识点:双指针,枚举。

对于区间内的一个位置 \(i\) ,当左端点 \(l\) 满足 \(i-a[i]+1\leq l\) 时,\(i\) 才能可能存在于 \(l\) 开始的区间。

同时,注意到区间端点具有单调性,即 \([l,r]\) 是一个合法区间,那么 \([i,r],i\in[l,r]\) 都是合法区间,因此可以尺取法枚举左端点 \(l\) ,找到第一个不可行右端点 \(r\) ,就直接得到从 \(l\) 为左端点的区间个数 \(r-l\) 。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; int a[200007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
int l = 1, r = 1;
ll ans = 0;
while (l <= n) {
while (r <= n) {
if (r + 1 - a[r] > l) break;
r++;
}
ans += r - l;
l++;
}
cout << ans << '\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;
}

C2

题解

知识点:前缀和,双指针,枚举。

此题能用线段树二分做,但实际上二分查找右端点没有必要,可以尺取法中同时预处理出来。

先考虑修改 \(a[p]\) 到 \(x\) 会改变什么。如果 \(x > a[p]\) ,那么一些原本右端点被 \(p\) 阻挡的区间现在可能跨越 \(p\) 再往后走一段;如果 \(x<a[p]\) ,那么原本一些跨越了 \(p\) 的区间右端点现在可能会被 \(p\) 阻挡(\(\geq p\) 的不受影响接下来不讨论)。

明确了修改 \(a[p]\) 会导致的变化,那就开始具体讨论:

  1. \(x < a[p]\) ,我们首先需要知道跨越了 \(p\) 的具体区间是什么才能进行下一步操作。因为区间端点是单调的,我们只需要知道第一个右端点可以跨越 \(p\) 的左端点即可,那么到 \(p-1\) 为止的左端点都是可以跨越 \(p\) 的。

    我们在尺取法中扩展右端点时,用 \(Lr[r]\) 记录以 \(r\) 为右端点的左端点,由于每个 \(r\) 只会记录一次,那么 \(Lr[r]\) 一定代表第一次以 \(r\) 为右端点可行的左端点 \(l\) ,所以 \(Lr[p]\) 即区间右端点能跨越 \(p\) 的第一个左端点。

    接下来要考虑 \(a[p]\) 修改成 \(x\) 之后影响了左端点 \([Lr[p],p-1]\) 的哪一部分。显然, \(x\) 在位置 \(p\) 作为右端点时,左端点的可能范围是 \([p-x+1,p-1]\) 。那么只有在 \(p-x+1 > Lr[p]\) 时,才会使 \([Lr[p],p-x]\) 这些原本能跨越 \(p\) 的左端点的右端点被 \(p\) 阻挡,否则不会影响答案。

    因此,我们设前缀和 \(pre[i]\) 代表 \([1,i]\) 的点作为左端点产生的合法区间个数。我们先减去 \([Lr[p],p-x]\) 这部分左端点原本提供的区间个数,再加上新的个数,即 \(\sum_{i = Lr[p]}^{p-x} p-i = \dfrac{(p-Lr[p]+x)(p-x-Lr[p]+1)}{2}\) ,每个左端点 \(i\) 被 \(p\) 阻挡提供 \(p-i\) 个区间。所以最终答案为 \(pre[n] - (pre[p-x]-pre[Lr[p]-1]) + \dfrac{(p-Lr[p]+x)(p-x-Lr[p]+1)}{2}\) 。

  2. \(x>a[p]\) ,同样我们先确定右端点被 \(p\) 阻挡的左端点区间。我们只需要在每个左端点 \(l\) 扩展不了时,记录一下此时的 \(r\) ,即 \(Ll[r] = l\) 来表示被 \(r\) 阻挡的左端点,同时对于每个 \(r\) 只记录一次,因此 \(Ll[r]\) 就代表第一个被 \(r\) 阻挡的左端点。

    在上文提到 \(Lr[r]\) 代表第一个可以跨越 \(r\) 的左端点,那 \(Lr[r]-1\) 就是最后一个被 \(r\) 阻挡的左端点。于是, \([Ll[p],Lr[p]-1]\) 就是被 \(p\) 阻挡的左端点区间。

    注意到,可能出现不存在左端点会被 \(p\) 阻挡,这时候 \(Ll[p]\) 应为初始化的值 \(0\) ,答案不变。否则,被 \(p\) 阻挡的左端点区间必然存在。

    同时,如果存在这样的区间,那么 \(p-a[p]+1\) 必然等于 \(Lr[p]\) 。因此如果 \(x<a[p]\) ,那么 \(p-x+1\) 一定小于 \(Lr[p]\) ,一定会改变答案。 于是,需要修改答案的左端点区间就是 \([\max(Ll[p],p-x+1),Lr[p]-1]\) 。

    最后我们还需要知道,这些左端点跨越了 \(p\) 之后的右端点最多到哪。在一开始的尺取法时,我们用 \(rr\) 来记录,当 \(l\) 被 \(r\) 阻挡时,跨越 \(r\) 后又会被阻挡的位置,那么 \(rr-l\) 即 \(l\) 跨越 \(r\) 后的合法区间的新个数。

    我们同样用前缀和记录一下,\(skpre[i]\) 代表 \([1,i]\) 的区间的左端点,可以跨越一次阻挡自己的位置后的合法区间个数。我们先减去 \([\max(Ll[p],p-x+1),Lr[p]-1]\) 的原本的答案 \(pre[Lr[p]-1] - pre[\max(Ll[p],p-x+1)-1]\) ,再加上新的个数 \(skpre[Lr[p]-1] - skpre[\max(Ll[p],p-x+1)-1]\) 。 所以最终答案为 \(pre[n] - (pre[Lr[p]-1] - pre[\max(Ll[p],p-x+1)-1]) + (skpre[Lr[p]-1] - skpre[\max(Ll[p],p-x+1)-1])\)

时间复杂度 \(O(n+q)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; int a[200007];
int Ll[200007], Lr[200007];
ll pre[200007], skpre[200007];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
int l = 1, r = 1, rr = 1;//l为目前起点,r为以l为左端点的第一个不行的点,rr为跨越障碍点后第一个不行的点
while (l <= n) {
while (r <= n && r - a[r] + 1 <= l) Lr[r++] = l;//Lr[r]为r左边第一个可行l,即左边最后一个以r为障碍的点+1
rr = min(max(rr, r + 1), n + 1);
while (rr <= n && rr - a[rr] + 1 <= l) rr++; if (!Ll[r]) Ll[r] = l;//Ll[r]为r左边第一个不可行l
pre[l] = pre[l - 1] + r - l;
skpre[l] = skpre[l - 1] + rr - l;
l++;
} int q;
cin >> q;
while (q--) {
ll ans = pre[n];
int p, x;
cin >> p >> x;
if (x < a[p] && p - x + 1 > Lr[p]) {
ans -= pre[p - x] - pre[Lr[p] - 1];
ans += 1LL * (x + p - Lr[p]) * (p - x - Lr[p] + 1) / 2;
}
else if (x > a[p] && Ll[p]) {
ans -= pre[Lr[p] - 1] - pre[max(p - x + 1, Ll[p]) - 1];
ans += skpre[Lr[p] - 1] - skpre[max(p - x + 1, Ll[p]) - 1];
}
cout << ans << '\n';
}
return 0;
}

D

题解

知识点:构造。

显然,\(1\) 或 \(0\) 的个数为奇数时一定不可能。

猜想,\(1\) 和 \(0\) 个数都为偶数时,一定能够造出。考虑两两构造成 \(s[i] = s[i+1]\) 的形式,如此只要取 \(i = 2k-1\) 即可。

当 \(s[i] = s[i+1]\) 时符合构造不需要修改,当 \(s[i] \neq s[i+1]\) 时考虑如下修改。

不符合我们构造形式的 \(01\) 组合一定是成对出现,比如 01 出现,因为 \(0\) 和 \(1\) 的个数都为偶数,那么一定会再出现一次 \(s[i] \neq s[i+1]\) 的组合来使个数为偶数。

我们考虑对第一个组合取出一个 \(0\) ,那么剩下一个 \(1\) ,需要从下一个组合取出一个 \(1\) 给这一组即可,那么下一组就会剩下一个 \(0\) ,再从下下一组取出一个 \(0\) ,以此类推。因为成对出现,所以取到最后一定取的是 \(1\) ,剩下一个 \(0\) ,那么把第一组取的 \(0\) 填上即可。

我们注意到上面取的过程,实际上就是右边一组往左边一组传递一个数字,第一组给最后一组传递一个数字,也就是题目给出的一次操作,于是就构造成功了。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; bool solve() {
int n;
string s;
cin >> n >> s;
if (count(s.begin(), s.end(), '1') & 1) return false;
s = '?' + s;
bool cur = 0;//cur代表上一组不同的缺的数字
vector<int> b;
for (int i = 1;i <= 2 * n;i += 2) {
if (s[i] != s[i + 1]) {
if (s[i] - '0' == cur) b.push_back(i), cur ^= 1;//取出上一组需要的数字,然后更换cur,往复循环
else b.push_back(i + 1), cur ^= 1;
}
}
cout << b.size() << ' ';
for (auto i : b) cout << i << ' ';
cout << '\n';
for (int i = 1;i <= 2 * n;i += 2) cout << i << ' ';
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;
}

Codeforces Round #825 (Div. 2) A-D的更多相关文章

  1. 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 ...

  2. Codeforces Round #354 (Div. 2) ABCD

    Codeforces Round #354 (Div. 2) Problems     # Name     A Nicholas and Permutation standard input/out ...

  3. Codeforces Round #368 (Div. 2)

    直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...

  4. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  5. Codeforces Round #279 (Div. 2) ABCDE

    Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems     # Name     A Team Olympiad standard input/outpu ...

  6. 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 ...

  7. 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 ...

  8. Codeforces Round #371 (Div. 1)

    A: 题目大意: 在一个multiset中要求支持3种操作: 1.增加一个数 2.删去一个数 3.给出一个01序列,问multiset中有多少这样的数,把它的十进制表示中的奇数改成1,偶数改成0后和给 ...

  9. Codeforces Round #268 (Div. 2) ABCD

    CF469 Codeforces Round #268 (Div. 2) http://codeforces.com/contest/469 开学了,时间少,水题就不写题解了,不水的题也不写这么详细了 ...

  10. 贪心+模拟 Codeforces Round #288 (Div. 2) C. Anya and Ghosts

    题目传送门 /* 贪心 + 模拟:首先,如果蜡烛的燃烧时间小于最少需要点燃的蜡烛数一定是-1(蜡烛是1秒点一支), num[g[i]]记录每个鬼访问时已点燃的蜡烛数,若不够,tmp为还需要的蜡烛数, ...

随机推荐

  1. 【MLA】内存泄漏检查

    项目地址:skullboyer/MLA (github.com) 介绍 MLA 即 Memory Leak Analyzer,是一个排查内存泄漏的分析器 实现机制是在malloc时记录分配位置信息,在 ...

  2. 什么是 doris,为什么几乎国内大厂都会使用它

    转载至我的博客 https://www.infrastack.cn ,公众号:架构成长指南 今天给各位分享一个非常牛的实时分析型数据库Apache Doris,几乎国内的一二线大厂都在使用它做数据分析 ...

  3. Python Code_01

    author : 写bug的盼盼 development time : 2021/8/27 19:41 输出数字 print(520) 输出字符串 print('HelloWorld') print( ...

  4. MySQL为什么不推荐使用in

    有的时候博客内容会有变动,首发博客是最新的,其他博客地址可能会未同步,认准https://blog.zysicyj.top 首发博客地址 系列文章地址 当使用IN语句时,MySQL可能会遇到以下问题: ...

  5. [转帖]容器化 TCP Socket 缓存、接收窗口参数

    https://blog.mygraphql.com/zh/notes/low-tec/network/tcp-mem/#rmem_default 最近需要支持一个单 POD 的 TCP 连接数上 1 ...

  6. [转帖]nacos discovery和config

    微服务和nacos版本都在2.x及之后. 1.discovery用于服务注册,将想要注册的服务注册到nacos中,被naocs发现. pom引入的依赖是: yml配置文件中: 2.config用于获取 ...

  7. [转帖]疑问:进程在竞争CPU时并没有真正运行,为什么还会导致系统的负载升高?

    疑问:进程在竞争CPU时并没有真正运行,为什么还会导致系统的负载升高? 因为存在CPU上下文切换. linux系统说明 Linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行.当然,这些 ...

  8. 信创-飞腾CPU路线图

  9. JAVA多线程并发编程-避坑指南

    作者:京东零售 肖朋伟 一.前言 开发过程中,多线程的应用场景可谓十分广泛,可以充分利用服务器资源,提高程序处理速度.我们通常也会使用池化技术,去避免频繁创建和销毁线程. 本篇旨在基于编码规范.工作中 ...

  10. 【JS 逆向百例】网洛者反爬练习平台第五题:控制台反调试

    关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后 ...