Codeforces Round #825 (Div. 2) A-D
A
题解
知识点:贪心。
考虑两种方法:
- 所有不同的位置使用操作1变成相同
- 使用操作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])\) ,则:
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]\) 会导致的变化,那就开始具体讨论:
\(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}\) 。
\(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的更多相关文章
- 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后和给 ...
- Codeforces Round #268 (Div. 2) ABCD
CF469 Codeforces Round #268 (Div. 2) http://codeforces.com/contest/469 开学了,时间少,水题就不写题解了,不水的题也不写这么详细了 ...
- 贪心+模拟 Codeforces Round #288 (Div. 2) C. Anya and Ghosts
题目传送门 /* 贪心 + 模拟:首先,如果蜡烛的燃烧时间小于最少需要点燃的蜡烛数一定是-1(蜡烛是1秒点一支), num[g[i]]记录每个鬼访问时已点燃的蜡烛数,若不够,tmp为还需要的蜡烛数, ...
随机推荐
- C#操作 excel 表格
nuget引入: EPPlus.Core FileInfo file = new FileInfo(@"d:\test.xlsx"); using (ExcelPackage pa ...
- Go-获取指定长度随机字符串
// GetCode 获取一个随机用户唯一编号 func GetCode(codeLen int) string { // 1. 定义原始字符串 rawStr := "abcdefghijk ...
- [转帖]/etc/security/limits.conf 详解与配置
https://www.cnblogs.com/operationhome/p/11966041.html 一. /etc/security/limits.conf 详解 /etc/security/ ...
- 阿里的AIGC数据库工具: Chat2DB的学习与使用
阿里的AIGC数据库工具: Chat2DB的学习与使用 背景 今天陪家中老人去完医院后, 继续回来学习时发现 阿里巴巴的 chat2DB已经发布的 2.0.1的版本. 想着下载下来试试. 主要也是备忘 ...
- 申威3231服务器Redis性能验证-及最全信创CPU性能分析
申威3231服务器Redis性能验证-及最全信创CPU性能分析 背景 公司里面新进了几台服务器. 有台申威服务器. 因为前段时间参与过一次申威的POC验证. 当时对性能有一点简单的理解. 但是因为不方 ...
- [转帖]JVM NativeMemoryTracking ;jcmd process_id VM.native_memory;Native memory tracking is not enabled
目录 一.Native Memory Tracking (NMT) 是Hotspot VM用来分析VM内部内存使用情况的一个功能.我们可以利用jcmd(jdk自带)这个工具来访问NMT的数据. 1.N ...
- 初试高云FPGA
前言 之前一直眼馋Sipeed的Tang系列,正好遇到有工程需要高速控制并行总线,就买了NANO 9K和Primer 20K试试水 买回来先拆的贵的20k,结果发现Sipeed设计师有奇怪的脑回路: ...
- Protobuf中如何指定json tag
在 Protocol Buffers (protobuf) 中,可以使用特定的选项来指定生成的 JSON 标签.通过在消息定义中使用 [(json_name)] 选项,可以控制生成的 JSON 字段名 ...
- Fabric网络升级(总)
原文地址在这里. 在fabric网络中,升级nodes和通道至最新版本需要四步: 备份账本和MSPs. 以滚动的方式将orderer升级到最新版. 以滚动的方式将peers升级到最新版. 将order ...
- Origin2017、Origin2018详细安装教程
1.Origin2017安装 1.1 安装步骤: 解压安装包,打开"Origin2017"目录,双击"setup.exe"开始安装 安装步骤1,点击[下一步] ...