比赛链接

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的更多相关文章

  1. 【cf比赛记录】Codeforces Round #601 (Div. 2)

    Codeforces Round #601 (Div. 2) ---- 比赛传送门 周二晚因为身体不适鸽了,补题补题 A // http://codeforces.com/contest/1255/p ...

  2. Codeforces Round #601 (Div. 2)

    传送门 A. Changing Volume 签到. Code /* * Author: heyuhhh * Created Time: 2019/11/19 22:37:33 */ #include ...

  3. 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]块巧克力,每次操作可以将盒子中的 ...

  4. 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 ...

  5. Codeforces Round #601 (Div. 2) D Feeding Chicken

    //为了连贯,采取一条路形式,从第一行开始 也就是s型 #include <bits/stdc++.h> using namespace std; ; char str[MAXN][MAX ...

  6. Codeforces Round #601 (Div. 2) C League of Leesins

    把每一次输入的一组数字存下来,然后把每个数字出现的组数存下来 然后找只出现过一次的数字a,那么这个数字a不是开头就是结尾,默认为开头(是哪个都无所谓),然后去找和它出现在同一组的两个数字b和c,而b和 ...

  7. Codeforces Round #601 (Div. 2) B Fridge Lockers

    //题目要求的是每一个点最少要有两条边连接,所以可以先构成一个环.然后再把剩余的最短的边连接起来 #include<iostream> #include<algorithm> ...

  8. Codeforces Round #601 (Div. 2) A Changing Volume

    好吧,其实我拿到这个题的时候,首先想到了bfs,写完之后,开开森森的去交代码,却在第二个数据就TEL,然后优化半天,还是不行. 最终,我盯着1,2,5发呆半天,wc,然后直接贪心 #include&l ...

  9. Codeforces Round #601 (Div. 2)E(寻找质因子,DP)

    先分解质因数,对于当前a[i],假设当前的质因数为x,这个位置要满足能被k整除,有两个可能,要么是它向后一个转移x%k个,要么是后一个向它转移k-x%k个. 对于每一个a[i]满足后,因为只会对下一个 ...

  10. Codeforces Round #601 (Div. 2)D(蛇形模拟)

    #define HAVE_STRUCT_TIMESPEC #include<bits/stdc++.h> using namespace std; vector<char>an ...

随机推荐

  1. Linux进程间通信(二)

    信号 信号的概念 信号是Linux进程间通信的最古老的一种方式.信号是软件中断,是一种异步通信的方式.信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断,转而处理某个突发事件. 一旦产生信号 ...

  2. "xxx cannot be cast to jakarta.servlet.Servlet "报错解决方式

    在做jsp的上机时候同学出现了一个500错误:com.kailong.servlet.ComputeBill cannot be cast to jaka.servlet.Servlet 然后因为我用 ...

  3. select中DISTINCT的应用-过滤表中重复数据

    在表中,一个列可能会包含多个重复值,有时也许希望仅仅列出不同(distinct)的值. DISTINCT 关键词用于返回唯一不同的值. SQL SELECT DISTINCT 语法 SELECT DI ...

  4. 利用递归的方式在JSON 数据中找到某个节点的多有父节点

    在项目中遇到的问题-- 一个级联题,知道答案id  后将每一级的选项展示出来 例如 级联题的 json 数据是 [ { name: '北京', id: 1, children:[ { name: '朝 ...

  5. 关于model,modelsmanager,db以及phql之间关系的梳理

    摘要: model在前,db在model后面作为驱动支持.phql是phalcon自创的查询语言,主要特性是在sql语句中用模型名替代表名,其聪明地解析模型类,包括关联关系等,还支持参数绑定.mode ...

  6. 优雅的重启uwsgi 告别uwsgi reload过程中造成的无法请求、请求延迟等问题

    [uwsgi]#使用优雅重启 lazy-apps = true #监听monitor文件 当monitor文件发生改变是重启uwsgi touch-chain-reload = /home/monit ...

  7. UBOOT编译--- UBOOT的顶层config.mk(五)

    1. 前言 UBOOT版本:uboot2018.03,开发板myimx8mmek240. 2. 概述 此文件包含在 ./Makefile 和 spl/Makefile 中. 清理状态以避免添加两次相同 ...

  8. 生成requirements.txt

    requirements.txt文件 requirements.txt 文件是项目的依赖包及其对应版本号的信息列表,即记载你这个项目所安装的依赖. 作用:用来重新构建项目或者记录项目所需要的运行环境依 ...

  9. Blender修改视野范围

    首先,我不是专门的建模人员.但是有时候会拿到建模人员的制作的模型导入进行修改. 比如简单的删除某个模型,调整模型的尺寸. 还有就是调整模型的建模中心点,这点有时候显得特别重要,模型的中心点偏离较大会给 ...

  10. Redis Zset实现统计模块

    1. 背景 公司有一个配置中心系统,使用MySQL存储了大量的配置,但现在不清楚哪些配置正在线上使用,哪些已经废弃了,所以需要实现一个统计模块,实现以下两个功能: 查看总体配置的数量以及活跃的数量 查 ...