比赛链接

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]]\) ,随后从小到大构造:

  1. 数字没出现过,那么可以放入队列 \(qu\) ,用于补齐出现两次的数字的空位。
  2. 数字只出现了一次,假设出现在 \(a_i\) ,那么令 \(p_i = q_i = a_i\) 是最优的。因为 \(p_i,q_i\) 其中一个可以更小,但小的数字可能要用于填充别的地方,所以最优解是填两个相等的。
  3. 数字出现了两次,假设出现在 \(a_i = a_j = a\) ,那么令 \(p_i = q_j = a\) ,设 \(qu\) 里队首元素为 \(x\) ,令 \(q_i = p_j = x\) 。因为是从小到大构造,所以 \(qu\) 里的元素一定是比 \(a\) 小的,所以可以用来填充空位;如果队空,则无解。
  4. 数字出现三次及以上,无解。

时间复杂度 \(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. 一个环被裂解成两个环
  2. 两个环被合并成一个环

前提是不破坏相对元素的位置,例如 \(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的更多相关文章

  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. Vue学习之--------消息订阅和发布、基础知识和实战应用(2022/8/24)

    文章目录 1.基础知识 2.代码实例 2.1 main.js 2.2 School.vue 2.3 Student.vue 2.4 App.vue 3.全局事件总线通信改为消息的订阅和发布 3.1 核 ...

  2. DelCrLfSpace V0.9

    开发界面 Option Explicit 'SourceTextBox 是上面的源框 'ResultTextBox 是下面的处理预览框 'Form KeyPreview = True Private ...

  3. 怎么样子盒子能撑起父盒子?浮动,BFC,边距重叠

    怎么样子盒子能撑起父盒子? 从行内元素跟块元素来看: 一般情况下,行内元素只能包含数据和其他行内元素. 而块级元素可以包含行内元素和其他块级元素. 块级元素内部可以嵌套块级元素或行内元素. 建议行内元 ...

  4. Hutool 的学习

    1. Hutool 介绍 Hutool 是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以"甜甜 ...

  5. golang内置包管理工具go mod简明教程

    go mod go buildin package manager. go mod是go语言内置的包管理工具,集成在go tool中,安装好go就可以使用. 要求: go version >= ...

  6. Android Studio打开时报错if you already hava 64-bit JDK installed,define a JAVA_HOME

    出现这个问题不知道改了什么导致的,卸载了重新安装也是不行. 以及到高级设置中进行配置jdk也是无效, 解决方法为需要在路径 C:\Users\你自己的用户名\AppData\Roaming\Googl ...

  7. php中的try语句

    为了进一步处理异常,我们需要使用try-catch语句----包括Try语句和至少一个的catch语句.任何调用 可能抛出异常的方法的代码都应该使用try语句.Catch语句用来处理可能抛出的异常.以 ...

  8. 更改grub2背景图片

    在/etc/grub/default这里面修改东西然后update-grub来间接修改/boot/grub/grub.cfg中的内容 1.将png图片放进/boot/grub/目录下 2.update ...

  9. 解决一个mysql报错

    问题描述 insert into btsync (key,title) values ('a','b'); ERROR 1064 (42000): You have an error in your ...

  10. 安装mySql 出现 one more product requirements have not been satisified

    安装mySql 出现 one more product requirements have not been satisified 原因是缺少一些依赖环境. 在弹出的对话框中点击 否. 然后点击执行, ...