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 ...
随机推荐
- Elasticsearch rest-high-level-client 基本操作
Elasticsearch rest-high-level-client 基本操作 本篇主要讲解一下 rest-high-level-client 去操作 Elasticsearch , 虽然这个客户 ...
- Python数据分析:实用向
文件处理 导包 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns ...
- 死磕面试系列,Java到底是值传递还是引用传递?
Java到底是值传递还是引用传递? 这虽然是一个老生常谈的问题,但是对于没有深入研究过这块,或者Java基础不牢的同学,还是很难回答得让人满意. 可能很多同学能够很轻松的背出JVM.分布式事务.高并发 ...
- ES6高级编程(一)
一.JavaScript概要 1.1.JavaScript组成 JavaScript主要由三部分构成,分别是ECMAScript.DOM与BOM ECMAScript定义了该语言的语法.类型.语句.关 ...
- Go语言核心36讲44
今天,我们来讲另一个与I/O操作强相关的代码包bufio.bufio是"buffered I/O"的缩写.顾名思义,这个代码包中的程序实体实现的I/O操作都内置了缓冲区. bufi ...
- Crond服务+Shell实现秒级任务
服务 [root@19-v1-centos-6 ~]# chkconfig --list | grep crond crond 0:off 1:off 2:on 3:on 4:on 5:on 6:of ...
- Spring Cloud Gateway 使用示例
Spring Cloud Gateway 使用示例 作者: Grey 原文地址: 博客园:Spring Cloud Gateway 使用示例 CSDN:Spring Cloud Gateway 使用示 ...
- 解决Linux使用deepin-wine跑qq,tim打不开文件所在文件夹
前言 使用deepin-wine 跑qq,发现一个小bug 这里点击打开文件夹是没有效果的,包括在 tim 上也是这样 问题原因 出现这个问题是因为 deepin-wine 跑的 QQ,Tim 打开文 ...
- Windows 10 读取bitlocker加密的硬盘出现参数错误怎么解决?
我为了数据安全,用windows专业版的bitlocker加密了一个固态硬盘SSD做的移动硬盘(u盘同理),在家里电脑(windows10 家庭版)打开的时候出现了参数错误 即使密码输入正确还是这个错 ...
- Maven工程卡在Resolving Maven dependencies,长时间不变
添加:-Xms1024m -Xmx2048m 点apply.ok 秒解决