Codeforces Round #842 (Div. 2) A-D
A
题意
给一个数 \(k\) 找到最大的 \(x\) ,满足 \(1 \leq x < k\) 且 \(x!+(x-1)!\) 是 \(k\) 的倍数。
题解
知识点:数学。
猜测 \(x = k-1\) ,证明 \((k-1)! + (k-2)! = (k-1+1) \cdot(k-2)! = k \cdot (k-2)!,k \geq 2\) 。
因此 \(x = k-1\) 。
时间复杂度 \(O(1)\)
空间复杂度 \(O(1)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool solve() {
int k;
cin >> k;
cout << k - 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
题意
给一个长为 \(n\) 的排列,每次操作从排列中取出 \(k\) 个数,从小到大排序好放回排列尾部。问最少操作多少次,才能将原排列变成从小到大排序好的排列。
题解
知识点:贪心。
注意到每次操作都会把数字放到尾部,不会影响之前数字的相对位置。因此为了使得操作最小化,我们先找到不用选的数字有多少,显然我们需要从 \(1\) 开始递增往后找。设 \(pos\) 是第一个要选的数字,那么答案便是 \(\Big\lceil \dfrac{n - pos + 1}{k} \Big\rceil\) 。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[100007];
bool solve() {
int n, k;
cin >> n >> k;
for (int i = 1;i <= n;i++) cin >> a[i];
int pos = 1;
for (int i = 1;i <= n;i++) {
if (pos == a[i]) pos++;
}
cout << (n - pos + 1 + k - 1) / k << '\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
题意
给出 \(n\) 个数 \(a_i\) ,要求两个长为 \(n\) 的排列 \(p,q\) 使得 \(a_i = \max(p_i,q_i)\) 。
题解
知识点:构造。
先记录每个数字出现的位置 \(pos[a[i]]\) ,随后从小到大构造:
- 数字没出现过,那么可以放入队列 \(qu\) ,用于补齐出现两次的数字的空位。
- 数字只出现了一次,假设出现在 \(a_i\) ,那么令 \(p_i = q_i = a_i\) 是最优的。因为 \(p_i,q_i\) 其中一个可以更小,但小的数字可能要用于填充别的地方,所以最优解是填两个相等的。
- 数字出现了两次,假设出现在 \(a_i = a_j = a\) ,那么令 \(p_i = q_j = a\) ,设 \(qu\) 里队首元素为 \(x\) ,令 \(q_i = p_j = x\) 。因为是从小到大构造,所以 \(qu\) 里的元素一定是比 \(a\) 小的,所以可以用来填充空位;如果队空,则无解。
- 数字出现三次及以上,无解。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[200007];
int p[200007], q[200007];
vector<int> pos[200007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i], pos[i].clear();
for (int i = 1;i <= n;i++) pos[a[i]].push_back(i);
queue<int> qu;
for (int i = 1;i <= n;i++) {
if (pos[i].size() > 2) return false;
if (pos[i].size() == 0) qu.push(i);//空闲数字放入队列
else if (pos[i].size() == 1) {
p[pos[i][0]] = i;
q[pos[i][0]] = i;
}//可以用小的但不是最优的
else {
if (qu.empty()) return false;//没有空闲的小的数字,无解
p[pos[i][0]] = i;
p[pos[i][1]] = qu.front();
q[pos[i][0]] = qu.front();
q[pos[i][1]] = i;
qu.pop();
}
}
cout << "YES" << '\n';
for (int i = 1;i <= n;i++) cout << p[i] << " \n"[i == n];
for (int i = 1;i <= n;i++) cout << q[i] << " \n"[i == 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;
}
D
题意
给一个长为 \(n\) 的排列,每次可以选择两个数交换,问最少交换几次可以使得排列逆序数为 \(1\) 。
题解
知识点:枚举,数学。
关于这类排列的题,都可以先进行一个构造,连接所有 \(i \to a[i]\) ,图中会形成若干个环,称为置换环。例如 \(2,3,4,1,5\) ,可以得到 \(1,2,3,4\) 构成的环和 \(5\) 构成的环( \(5\) 是自环)。
我们进行一次交换操作 \((i,j)\),将使得 \(i \to a_i,j \to a_j\) 两条边变成 \(i \to a_j,j \to a_i\) 。这个操作在图中可以做到以下两个结果之一:
- 一个环被裂解成两个环
- 两个环被合并成一个环
前提是不破坏相对元素的位置,例如 \(1,3,2,4\) 环不可能分解成 \(1,2\) 和 \(3,4\) 环;\(1,2\) 和 \(3,4\) 环也不可能合并成 \(1,3,2,4\) 环。
举个例子,我们对 \(2,3,4,1,5\) 交换 \((2,4)\) ,则排列变成 \(2,1,4,3,5\) ,图中边 \(2 \to 3,4\to 1\) 变成 \(2 \to 1,4 \to 3\) ,即 \(1,2,3,4\) 环被拆成 \(1,2\) 和 \(3,4\) 两个环;或者交换 \((4,5)\) ,则排列变成 \(2,3,4,5,1\) ,图中边 \(4 \to 1,5 \to 5\) 变成 \(4 \to 5,5 \to 1\) ,即 \(1,2,3,4\) 和 \(5\) 环被合成为 \(1,2,3,4,5\) 环。
回到题目。题目要求的最终状态化成图后,实际上就是一组相邻元素成环,剩下的元素自环。
我们对原排列化为置换环图,假设这些环中已经有至少一组相邻元素(环中位置不一定需要相邻,因为可以通过操作使其相邻),如 \(1,4,2\) 环就有 \(1,2\) 两个相邻元素,我们可以在之后的操作中保留这组元素,把其他元素全都操作成自环即可;如果没有,那么先将元素都操作成自环,再多一次操作把一组相邻元素合并成环,如排列 \(3,4,5,2,1\) 有 \(1,3,5\) 和 \(2,4\) 环,一个相邻元素都没有。
假设 \(n\) 个元素的图中有 \(cnt\) 个环,那么如果我们需要把环中元素都操作成自环,实际上需要操作 \(n-cnt\) 次,因为每个环保留一个元素,剩下的元素都需要通过操作挪出来。再考虑相邻元素的结论,如果有相邻元素那么可以少操作一次 \(n-cnt-1\) ;否则需要多操作一次 \(n-cnt+1\) 。
环的实现可以看代码,和并查集类似但简单许多。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int a[200007];
int fa[200007];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i], fa[i] = -1;
int ans = n;
for (int i = 1;i <= n;i++) {
if (fa[i] != -1) continue;
int j = i;
ans--;//一个环减一次,
while (fa[j] == -1) {
fa[j] = i;//环内元素的根设为i
j = a[j];
}
}
bool ok = 0;
for (int i = 1;i <= n - 1;i++) ok |= fa[i] == fa[i + 1];//环内有一队相邻元素,可以少操作一次
cout << ans + (ok ? -1 : 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;
}
Codeforces Round #842 (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为还需要的蜡烛数, ...
随机推荐
- CRT & EXCRT 学习笔记
这玩意解决的是把同余方程组合并的问题. CRT的核心思想和拉格朗日插值差不多,就是构造一组\(R_i\)使得$\forall i,j(i \neq j) $ \[R_im_i = 1, R_im_j ...
- 19.MongoDB系列之批量更新写入Groovy版
Groovy作为脚本,比Java在数据处理中具有更高的灵活性 // 获取mongo连接略 .... def count = 0 for(Township town : townships) { Doc ...
- Sql Server 数据库分页存储过程书写
create proc 存储过程名称( @page int, //pageindex @rows int, //pagesize @rowCount int out)as begin--定义字符串变量 ...
- k8s之pod连接被拒排查
k8s之pod连接被拒排查 pod链接被拒 查看pod的时候发现pod的状态为crashloopbackoff 然后看看日志发现报错如下 kubectl -n kf10 logs easydata-r ...
- PyGame做了一个扫雷
1 # 这是一个示例 Python 脚本. 2 3 # 按 ⌃R 执行或将其替换为您的代码. 4 # 按 双击 ⇧ 在所有地方搜索类.文件.工具窗口.操作和设置. 5 import sys 6 imp ...
- 【Bluetooth|蓝牙开发】二、蓝牙开发入门
个人主页:董哥聊技术 我是董哥,嵌入式领域新星创作者 创作理念:专注分享高质量嵌入式文章,让大家读有所得! [所有文章汇总] 1.蓝牙基础概念 蓝牙,是一种利用低功率无线电,支持设备短距离通信的无线电 ...
- Vue3的新特性
总概 1) 性能提升 打包大小减少 41% 初次渲染快 55%,更新渲染快 133% 内存减少 54% 使用 Proxy 代替 defineProperty 实现数据响应式 重写虚拟 DOM 的实现和 ...
- SQL server 操作相关
1.更改列的顺序后进行保存. 在SQL Server Management Studio中, "工具"--"选项"--"Designers" ...
- pip 国内源 包管理
配置国内源 linux配置 修改 ~/.pip/pip.conf 文件,如下,添加了源并修改了默认超时时间 [global] timeout = 3000 index-url = http://mir ...
- JVM运行时数据区域详解
参考文章: <Java Se11 虚拟机规范> <深入理解Java虚拟机-JVM高级特性与最佳实践 第3版>- 周志明 本文基于Java Se 11讲解. 根据<Java ...