Codeforces Round #601 (Div. 2) A-E
A
题意
给两个数字 \(a,b\) ,每次操作可以使 \(a\) 加上 \(+1,+2,+5,-1,-2,-5\) 中的一个数,求最少多少次操作可以将 \(a\) 变成 \(b\) 。
题解
知识点:贪心。
可以贪心取,先 \(5\) 后 \(2\) 再 \(1\) 。
一点小结论(可能是假的qwq):
考虑三个硬币 \(a>b>c\) ,令 \(a = kb+mc,b = nc\) 。
若 \(n - m \leq k\) 则任意数量的 \(a\) 都不可替代。
若 \(n - i(m-1)-1 \leq ik,i \geq 1\) ,则一次不能替代大于等于 \(i\) 个 \(a\) ,但可以用 \(jk+1\) 个 \(b\) 替代 \(j\) 个 \(a\) 和 \(n-jm\) 个 \(c\) ,其中 \(j<i\) 。
时间复杂度 \(O(1)\)
空间复杂度 \(O(1)\)
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
bool solve() {
int a, b;
cin >> a >> b;
int ans = abs(b - a) / 5 + abs(b - a) % 5 / 2 + abs(b - a) % 5 % 2;
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;
}
B
题意
有 \(n\) 个冰箱, \(m\) 个锁链,每个冰箱的价值为 \(a_i\) 。一个锁链可以连接两个冰箱,这两个冰箱就会被这条锁链锁住,而设置这条锁链的花费是连接的两个冰箱的价值之和。
要求你设置锁链使得每个冰箱至少被两条锁链锁住,并且花费最小。
题解
知识点:贪心,构造。
显然为了使得每个冰箱至少有两条锁链连着,那花费至少是编号总和乘 \(2\) ,考虑能否达成这个最小值。
显然,使用环形锁链结构,即可达成这个最小值,即 \(1 \to 2,2\to3,\cdots,n-1\to n,n \to 1\) ,而且用的锁链最少,为 \(n\) 条。
因此,若 \(n=2\) 或者 \(m<n\) 的情况,分别是不能构成环或锁链不够,那么是无解的。
时间复杂度 \(O(n)\)
空间复杂度 \(O(1)\)
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
bool solve() {
int n, m;
cin >> n >> m;
int ans = 0;
for (int i = 1;i <= n;i++) {
int x;
cin >> x;
ans += x;
}
if (n == 2 || m < n) return false;
cout << 2 * ans << '\n';
for (int i = 1;i < n;i++) {
cout << i << ' ' << i + 1 << '\n';
}
cout << n << ' ' << 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;
}
C
题意
有一个长为 \(n\) 的排列 \(p\) ,生成一个长为 \(n-2\) 的三元组序列 \(q\) ,其中 \(q_i = (p_i,p_{i+1},p_{i+2})\) 。
现在给你被打乱的 \(q\) ,即每个三元组内部被打乱, \(q\) 的排序也被打乱,求符合 \(q\) 的一个 \(p\) 。
题解
知识点:构造。
注意到 \(p\) 生成的 \(q\) 中,数字出现的次数是有规律的。 \(p_1,p_n\) 恰好出现一次, \(p_2,p_{n-1}\) 恰好出现两次,其余元素都会恰好出现三次。通过这个性质我们就能初步断定出现一次的一定在首或尾,出现两次的一定在第二个或倒数第二个,其余元素不确定。
因此,我们先预处理所有数出现的次数,同时维护每个数与其他数是否在同一个元组的关系。之后,我们可以先取一个出现一次的数作为 \(p_1\) ,那么 \(p_1\) 所在元组就没用了,我们把与 \(p_1\) 在一个元组里的数的次数减一,此时出现新的出现次数为 \(1\) 的数,他就是紧接着的第二个数,以此类推取数即可。
但是有一个特例,最后 \(5\) 个数的时候呈现 \(1,2,3,2,1\) ,取走一个 \(1\) 的数以后呈现 \(1,2,2,1\) ,再取一次就变成 \(1,1,1\) ,出现了三个 \(1\) 没法判断了,因此,我们要在一开始确定 \(p_1\) 的时候,直接把 \(p_{n-1},p_{n}\) 都确定了,这样到最后三个不确定的数中已经有两个确定过了就可以直接判断了。于是,我们开一个数组 \(vis\) 记录数有没有被取过,一开始把 \(p_{n-1},p_n\) 取走就行。
时间复杂度 \(O(n)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int cnt[100007];
vector<int> g[100007];
bool vis[100007];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 1;i <= n - 2;i++) {
int u, v, w;
cin >> u >> v >> w;
cnt[u]++;
cnt[v]++;
cnt[w]++;
g[u].push_back(v);
g[v].push_back(u);
g[u].push_back(w);
g[w].push_back(u);
g[v].push_back(w);
g[w].push_back(v);
}
vector<int> st;
for (int i = 1;i <= n;i++) {
if (cnt[i] == 1) st.push_back(i);
}
int fst = st[0];
int lst = st[1];
vis[fst] = vis[lst] = 1;
int lst2;
for (auto v : g[lst]) {
if (cnt[v] == 2) {
vis[v] = 1;
lst2 = v;
break;
}
}
for (int u = fst, w = 0;u;u = w) {
w = 0;
cout << u << ' ';
for (auto v : g[u]) {
if (vis[v]) continue;
cnt[v]--;
if (cnt[v] == 1) w = v;
}
}
cout << lst2 << ' ' << lst << '\n';
return 0;
}
D
题意
给一张 \(r \times c\) 的地图,地图上有米 R
和空地 .
。
现在有 \(k\) 只鸡,鸡的行走规则是只能从一格走到相邻的四格,地图上的格子鸡都能走。
现在让你给每只鸡分配 \(1\) 个区域,鸡只能在自己的区域里走,行走规则不变,要求每个鸡能吃到米的数量中的极差(最大值与最小值的差)最小。
题解
知识点:贪心,数学。
注意到,实际上我们可以给任意鸡分配任意的米数,只要我们走蛇形分配区域,就能保证区域一定是连通的。
设总米数为 \(sum\) ,考虑给每只鸡先分配 \(\left\lfloor \dfrac{sum}{k} \right\rfloor\) 个米,多出来的 \(sum \bmod k\) 个米一人一个分配完,这样极差最小。
时间复杂度 \(O(rc)\)
空间复杂度 \(O(rc)\)
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
char dt[107][107];
bool solve() {
int r, c, k;
cin >> r >> c >> k;
int sum = 0;
for (int i = 1;i <= r;i++) {
for (int j = 1;j <= c;j++) {
cin >> dt[i][j];
if (dt[i][j] == 'R') sum++;
}
}
int avg = sum / k;
int rst = sum % k;
int pos = 0, cnt = 0;
for (int i = 1;i <= r;i++) {
if (i & 1) {
for (int j = 1;j <= c;j++) {
if (dt[i][j] == 'R') cnt++;
if (cnt > avg + (rst > 0)) {
cnt = 1;
pos++;
if (rst > 0) rst--;
}
if (pos < 10) dt[i][j] = pos + '0';
else if (10 <= pos && pos < 36) dt[i][j] = pos - 10 + 'A';
else dt[i][j] = pos - 36 + 'a';
}
}
else {
for (int j = c;j >= 1;j--) {
if (dt[i][j] == 'R') cnt++;
if (cnt > avg + (rst > 0)) {
cnt = 1;
pos++;
if (rst > 0) rst--;
}
if (pos < 10) dt[i][j] = pos + '0';
else if (10 <= pos && pos < 36) dt[i][j] = pos - 10 + 'A';
else dt[i][j] = pos - 36 + 'a';
}
}
}
for (int i = 1;i <= r;i++) {
for (int j = 1;j <= c;j++) {
cout << dt[i][j];
}
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;
}
E
题意
给 \(n\) 个数 \(a_i\) ,每次操作可以任选一个数 \(a_i\) 减 \(1\) 并在 \(a_{i-1},a_{i+1}\) 中选择一个加 \(1\) (如果存在的话),即 \(a_i\) 给它的一个邻居一个 \(1\) 。
要求使用最少的操作次数,使得存在一个 \(k>1\) 能整除所有数。
Easy版 \(n \in [1,10^5],a_i \in \{ 0,1\}\)
Hard版 \(n \in [1,10^6],a_i \in [1,10^6]\)
题解
知识点:质因数分解,贪心,枚举。
如果最后 \(k\) 能整除 \(a_i\) ,等价于 \(k\) 能整除 \(sum = \sum a_i\) ,而总和是不变的,因此我们可以直接通过 \(sum\) 的因子求出 \(k\) 的可行值来枚举。
显然,对于 \(10^{12}\) 的数,枚举他的全部因子的复杂度是不可行的。实际上,并不是所有 \(k\) 都需要枚举的,我们只需要枚举 \(sum\) 的质因子 \(k\) 即可,因为对于一个合数因子的答案,他的质因子的答案不会更坏。质因子最多 \(12\) 个,复杂度完全可以接受。所以,我们先处理出 \(sum\) 的质因子 \(pfactor\) 数组,随后遍历求出操作取最小值。
对于一个确定的 \(k\) ,我们希望得到修改 \(a_i\) 数组的最小操作次数。我们可以从左往右遍历,假设前 \(i-1\) 个都已经能被整除,那么 \(a_i\) 没有必要对 \(a_{i-1}\) 操作了, 只可能把 \(a_i \bmod k\) 个 \(1\) 给 \(a_{i+1}\) 或者让 \(a_{i+1}\) 给自己 \(k - a_i \bmod k\) 个 \(1\) ,从中取最小值就是 \(a_i\) 需要的操作。
注意,前 \(i-1\) 能被 \(k\) 整除后,前 \(i-1\) 个数的操作最后都积累到 \(i\) 身上了,因此对于 \(a_i\) ,它已经变成 \((\sum_{j=1}^i a_i) \bmod k\) 。因此,令 \((\sum_{j=1}^i a_i) \bmod k = pre_i\) ,我们每次取最小值时,实际上是取 \(\min (pre_i,k-pre_i)\) 。
特判 \(sum = 1\) 的情况无解。
对于easy版:
我们可以直接枚举因子 \(k\) ,总数是 \(100\) 量级。
我们对一个 \(k\) 求最小操作时,可以直接贪心地每 \(k\) 个 \(1\) 分区域,每个区域的操作最小值是 \(k\) 个数到第 \(\left\lceil \dfrac{k}{2}\right\rceil\) 个数的距离总和(因为 \(a_i\) 都是 \(1\) ,代价等价于距离)。证明方法:可以设 \(f(x)\) 为选择到第 \(x\) 个数的距离总和,通过作差 \(f(x+1)-f(x)\) 发现是一个单谷函数,极值点在 \(x = \left\lceil \dfrac{k}{2}\right\rceil\) 。
时间复杂度 \(O(n+\sqrt{\sum a_i})\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int a[1000007];
void get_pfactor(ll n, vector<ll> &pfactor) {
for (int i = 2;1LL * i * i <= n;i++) {
if (n % i == 0) {
pfactor.push_back(i);
while (n % i == 0) n /= i;
}
}
if (n > 1) pfactor.push_back(n);
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
ll sum = 0;
for (int i = 1;i <= n;i++) cin >> a[i], sum += a[i];
if (sum == 1) {
cout << -1 << '\n';
return 0;
}
vector<ll> pfactor;
get_pfactor(sum, pfactor);
ll ans = 1e18;
for (auto p : pfactor) {
ll pre = 0, cnt = 0;
for (int i = 1;i <= n;i++) {
(pre += a[i]) %= p;
cnt += min(pre, p - pre);
}
ans = min(ans, cnt);
}
cout << ans << '\n';
return 0;
}
Codeforces Round #601 (Div. 2) A-E的更多相关文章
- 【cf比赛记录】Codeforces Round #601 (Div. 2)
Codeforces Round #601 (Div. 2) ---- 比赛传送门 周二晚因为身体不适鸽了,补题补题 A // http://codeforces.com/contest/1255/p ...
- Codeforces Round #601 (Div. 2)
传送门 A. Changing Volume 签到. Code /* * Author: heyuhhh * Created Time: 2019/11/19 22:37:33 */ #include ...
- Codeforces Round #601 (Div. 2) E2. Send Boxes to Alice (Hard Version)
Codeforces Round #601 (Div. 2) E2. Send Boxes to Alice (Hard Version) N个盒子,每个盒子有a[i]块巧克力,每次操作可以将盒子中的 ...
- Codeforces Round #601 (Div. 2) E1 Send Boxes to Alice (Easy Version)
#include <bits/stdc++.h> using namespace std; typedef long long ll; ; int a[N]; int n; bool pr ...
- Codeforces Round #601 (Div. 2) D Feeding Chicken
//为了连贯,采取一条路形式,从第一行开始 也就是s型 #include <bits/stdc++.h> using namespace std; ; char str[MAXN][MAX ...
- Codeforces Round #601 (Div. 2) C League of Leesins
把每一次输入的一组数字存下来,然后把每个数字出现的组数存下来 然后找只出现过一次的数字a,那么这个数字a不是开头就是结尾,默认为开头(是哪个都无所谓),然后去找和它出现在同一组的两个数字b和c,而b和 ...
- Codeforces Round #601 (Div. 2) B Fridge Lockers
//题目要求的是每一个点最少要有两条边连接,所以可以先构成一个环.然后再把剩余的最短的边连接起来 #include<iostream> #include<algorithm> ...
- Codeforces Round #601 (Div. 2) A Changing Volume
好吧,其实我拿到这个题的时候,首先想到了bfs,写完之后,开开森森的去交代码,却在第二个数据就TEL,然后优化半天,还是不行. 最终,我盯着1,2,5发呆半天,wc,然后直接贪心 #include&l ...
- Codeforces Round #601 (Div. 2)E(寻找质因子,DP)
先分解质因数,对于当前a[i],假设当前的质因数为x,这个位置要满足能被k整除,有两个可能,要么是它向后一个转移x%k个,要么是后一个向它转移k-x%k个. 对于每一个a[i]满足后,因为只会对下一个 ...
- Codeforces Round #601 (Div. 2)D(蛇形模拟)
#define HAVE_STRUCT_TIMESPEC #include<bits/stdc++.h> using namespace std; vector<char>an ...
随机推荐
- nordic——nrf52系列SWD设置回读保护
在开发时可能需要回读保护功能,在产品出厂后这个功能可以让你的代码更加安全,无法用SEGGER或者其余方式读取你的代码HEX文件,也就是禁用SWD下载接口.但是SWD锁住了,还想使用(从新下载代码)也是 ...
- Python--网络编程学习笔记系列02 附:tcp服务端,tcp客户端
Python--网络编程学习笔记系列02 TCP和UDP的概述: udp通信模型类似于写信,不需要建立相关链接,只需要发送数据即可(现在几乎不用:不稳定,不安全) tcp通信模型类似于打电话,一定要建 ...
- Linux之Docker-01
一.镜像基础命令 1.docker version [root@DY-Ubuntu-01 ~]#docker version #查看 Docker 版本 2.docker ...
- 常用CSS样式属性
01.常用样式 1.1.background背景 设置元素背景的样式 background,更好的衬托内容. 属性 描述 值 background 背景属性简写.支持多组背景设置,逗号,隔开 back ...
- Python的几种lambda排序方法
1.对单个变量进行排序 #lst = [[5,8],[5,3],[3,1]] lst.sort(key = lambda x : x[1]) #lst = [[3,1],[5,8],[5,3]] 以元 ...
- Marktext语法——Emoji表情大全
个人名片: 对人间的热爱与歌颂,可抵岁月冗长 Github:念舒_C.ying CSDN主页️:念舒_C.ying 个人博客 :念舒_C.ying People ️ ️ ️ ️ ♀️ ♀️ ♂ ...
- 1759D(数位变0)
题目链接 题目大意: 给你两个整数n, m.你需要求一个数,它满足如下条件: 是n的整数倍,且倍数小于m. 你应该使其末尾的0尽可能的多(如100后面有2个零,1020后面有一个零,我们应该输出100 ...
- PHY驱动调试之 ---PHY设备驱动(三)
1. 前言 内核版本:linux 4.9.225,以freescale为例.(部分内容待修改和补充,不一定准确) 2. 概述 上一篇文章讲了控制器的驱动使用的是platform总线的连接方式,本节要讲 ...
- (工具) 交叉编译 gperftools及使用
交叉编译gperftools及使用 sudo apt-get install kcachegrind # 导出为 callgrind 格式时需要 sudo apt install doxygen-la ...
- vue-element Form表单验证没错却一直提示错误
在使用element-UI 的表单时,发生一个验证错误,已输入值但验证的时候却提示没有输入 修改前 <el-form-item>中的prop绑定的是cus_name,而item里面的控件绑 ...