Codeforces Round #700 (Div. 2) A ~ E ,6题全,超高质量良心题解【每日亿题】2021/2/8
整理的算法模板合集: ACM模板
点我看算法全家桶系列!!!
实际上是一个全新的精炼模板整合计划
目录
- A - Yet Another String Game
- B - The Great Hero
- C. Searching Local Minimum
- D1 - Painting the Array I
- D2 - Painting the Array II
- E - Continuous City
这场打的头疼,先更一下C题吧,其他的几道题明天醒了再更…
现在脑子不太清醒,先口胡一个最简单的C吧…
来了来了,更一下 A ~ E
(实际上是昨天快两点才睡着,快九点了才起床,十点才吃完饭开始写
比赛链接:https://codeforces.com/contest/1480
A - Yet Another String Game
Problem 1480A - Yet Another String Game
Alice和 Bob 在玩游戏,Alice 先手,给定一个字符串,他们每次可以进行一个操作:让任意一个没有被选过的位置上的字符变成另一个不一样的字符。Alice 想让字符串最后的字典序最小,Bob 想让字符串最后的字典序最大,两位都会进行最优的操作,请问最后字符串会变成什么鬼样子 ~
Solution
签到题
模拟一下就行了,两位都尽量朝着自己的方向去选,所以Alice先选一定选第一个,然后 Bob 会选第二个,为了使得序列的字典序尽可能的打,所以就是奇偶交替进行…
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>using namespace std;const int N = 50007;int n, m, t;
string a, b;int main()
{scanf("%d", &t);while(t -- ) {cin >> a;int len = a.length();int cnt = 0, cnt1 = len, num = 0;for(int i = 0; i < len; ++ i){if(!(i & 1)) {if(a[i] == 'a') a[i] = 'b';else a[i] = 'a';}else {if(a[i] == 'z') a[i] = 'y';else a[i] = 'z';}}cout << a << endl;}return 0;
}
B - The Great Hero
Problem 1480B - The Great Hero
我们的攻击力为 AAA ,血量为 BBB ,面对 nnn 只怪,其中第 iii 只怪的攻击力为 aia_iai ,血量为 bib_ibi ,我们可以无限次地攻击任意一只怪,每次我们和怪都会掉血,规则参见正常的 RPG 游戏,就是当血量小于等于0时,死亡,每次我们和一只怪激情对砍,我们掉 aia_iai 的血量,怪掉 AAA 的血量,请问我们最后能否消灭所有的怪,哪怕在最后一击之后同归于尽。
Solution
一个简单的贪心。开始还以为是一个模拟,然后立马发现,因为可以同归于尽,所以我们最后一击要用到正确的地方。因为我们打的顺序无所谓,所以可能存在一种情况,我随便打,中间死了,但是我把攻击力最大的哪个怪,放到最后跟他同归于尽,就会最后死,答案从 NO
变成了 YES
。
然后再来分析这么解决。
首先很明显,对于第 iii 只怪,我们需要 ⌈biA⌉\lceil \frac{b_i}{A} \rceil⌈Abi⌉ 次才能打死它,然后每次会掉 aia_iai 的血,如果直接打死它的话,会掉 ⌈biA⌉×ai\lceil \frac{b_i}{A} \rceil\times a_i⌈Abi⌉×ai 的血。
所以我们就先模拟一遍,打一遍,然后最后的血量加上攻击力最大的那只怪的攻击力,相当于就是把这只放到最后打,要是加上之后的血量大于0,说明成功,否则中间就死了…
因为我特判的是 >0 而不是 >=0 ,我先扣掉了所有的血,再加上最大攻击力,如果我这时候剩余的血量 >0 说明我活到了最后一只攻击力最大的怪 例如这个
1
10 10 2
2 1000
50 10
答案就是NO,我的代码也是NO,我没办法活到1000的那个怪 ~
Code
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <unordered_map>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef int itn;
const int N = 5e5 + 7, M = 1e6 + 7, mod = 1e9 + 7;
const ll INF = 1e18 + 7;
ll n, m, t;
ll A, B;
PLL a[N];
bool solve()
{scanf("%lld%lld%lld", &A, &B, &n);ll maxx = -INF;for(int i = 1; i <= n; ++ i) {scanf("%lld", &a[i].x);maxx = max(maxx, a[i].x);}for(int i = 1; i <= n; ++ i) {scanf("%lld", &a[i].y);}ll sum = 0;for(int i = 1; i <= n; ++ i) {ll cnt = ceil(a[i].y * 1.0 / A);sum += cnt * a[i].x;}B -= sum;B += maxx;if(B > 0) return true;else return false;
}int main()
{scanf("%lld", &t);while(t -- ) {bool ans = solve();if(ans) puts("YES");else puts("NO");}return 0;
}
C. Searching Local Minimum
Problem 1479A - Searching Local Minimum
交互题,有一个 111 ~ nnn 的一个排列,只会给你 nnn 的值,求一个为 V 字形的数的下标。其中 V 字形数是指下标为 iii 的一个数, ai−1≥ai≤ai+1a_{i-1}\ge a_i\le a_{i+1}ai−1≥ai≤ai+1 ,想让你找到的这个 iii。你每次可以询问这个排列的一个下标的值,你最多可以问 100次。
1≤n≤1051\le n \le 10^51≤n≤105
Solution
因为题目要找的是一个 v 字形的数,也就是 ai−1≥ai≤ai+1a_{i-1}\ge a_i\le a_{i+1}ai−1≥ai≤ai+1 的这个 iii。
数据 10510^5105
如果 ai≤ai+1a_i\le a_{i+1}ai≤ai+1 那么 一定 ai≥ai−1a_i\ge a_{i-1}ai≥ai−1 ,不然 iii 就是答案。同理, ai≥ai−1a_i\ge a_{i-1}ai≥ai−1,那么 ai−1≥ai−2a_{i-1}\ge a_{i-2}ai−1≥ai−2 ,一次类推,一定是一个单调的
同理若 ai≥ai+1a_i\ge a_{i+1}ai≥ai+1 也一样单调,所以二分就行了,若 a[mid]
大于右边,则答案在左边…
没了,睡觉睡觉
Code
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <unordered_map>
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef int itn;
const int N = 5e3 + 7, M = 1e6 + 7, mod = 1e9 + 7;
const ll INF = 1e18 + 7;int n, m, t, k, q;
int a[N];
int vis[M];
PII ans[N];int ask(int x)
{printf("? %d\n", x);fflush(stdout);int res;scanf("%d", &res);return res;
}void solve()
{int l = 1, r = n;while(l < r) {int mid = l + r >> 1;int rr = ask(mid + 1);int midd = ask(mid);if(midd < rr) r = mid;else l = mid + 1;}printf("! %d\n", l);fflush(stdout);return ;
}int main()
{scanf("%d", &n);solve();return 0;
}
D1 - Painting the Array I
Problem 1479B1 - Painting the Array I
给你一个序列 aaa,请你将这个序列撕开分成两个序列 a(0)a^{(0)}a(0) 和 a(1)a^{(1)}a(1),使得将 a(0)a^{(0)}a(0) 和 a(1)a^{(1)}a(1) 合并所有相邻且相同的元素之后,两个序列剩余的元素个数和最大。
例如:
1 2 3 1
1 2 3 2
答案均为4。
Solution
我们发现直接遇见两个一样的就直接加2什么的暴力算的话不一定对,因为后面可能会出现多算的情况。就是你以为分开就好了,可以加,但是它却和放到的新序列的前一个元素重复,这样就多加了。
例如:
4 4 2 4 4
答案应该是 4 而不是 5 。
所以要考虑贪心,分类讨论后面可能会发生的情况。
我们一步一步分析。
我们首先设 a(0)a^{(0)}a(0) 序列的最后一个元素为 xxx ,a(1)a^{(1)}a(1) 的最后一个元素为 yyy 。
分类讨论,我们分别考虑什么情况的时候,把当前元素分配给哪一个序列会更优。
对于当前准备去分配的元素 z1z1z1,以及 z1z1z1 后面一位元素 z2z2z2。
(1) 考虑对前面的贡献
- 当
x == y
时,上下两个序列都无所谓。 - 当
x == z1 && y != z1
时,很明显分配给 yyy 会更优。 - 当
y == z1 && x != z1
时,很明显分配给 xxx 会更优。
(2) 考虑对后面的贡献
- 当
x == z2 && y != z2
时,很明显分配给 xxx 会更优,因为可能 z1z1z1 可以填上这个合并的漏洞,填不上的话,就算了,但会更优 - 当
y == z2 && x != z2
时,同理很明显分配给 yyy 会更优。 - 当
x == y == z2
那就无所谓了 ~ 给谁都行
剩余的所有情况应该像D2那样去判断与 xxx ,yyy 相同的元素的距离谁最近,就放到谁后面。具体思路 / 证明看下面的 D2 的题解,这里可能是因为数据较弱,所以过掉了,然后我也懒得改了 ~ (往下滑就看到了)
Code
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <unordered_map>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
typedef int itn;
const int N = 5e6 + 7, M = 6e6 + 7, mod = 1e9 + 7;
const ll INF = 1e18 + 7;int n, m, t, k;
itn a[N];
int vis[N];
void solve()
{int ans = 0;scanf("%d", &n);for(int i = 1; i <= n; ++ i) {scanf("%d", &a[i]);}int x = -1, y = -1;for(int i = 1; i <= n; ++ i) {itn z1 = a[i], z2 = a[i + 1];if(z1 == x && z1 == y) continue;if(z1 == x) {y = z1;ans ++ ;}else if(z1 == y) {x = z1;ans ++ ;}else {ans ++ ;if(z2 == x && z2 != y) {x = z1;}else if(z2 == y && z2 != x) {y = z1;}else x = z1;}}printf("%d\n", ans);
}int main()
{solve();return 0;
}
D2 - Painting the Array II
Problem 1479B2 - Painting the Array II
给你一个序列 aaa,请你将这个序列撕开分成两个序列 a(0)a^{(0)}a(0) 和 a(1)a^{(1)}a(1),使得将 a(0)a^{(0)}a(0) 和 a(1)a^{(1)}a(1) 合并所有相邻且相同的元素之后,两个序列剩余的元素个数和最小。
Solution
我们先按照上面 D1 的贪心策略分析。
我们首先设 a(0)a^{(0)}a(0) 序列的最后一个元素为 xxx ,a(1)a^{(1)}a(1) 的最后一个元素为 yyy 。
分类讨论,我们分别考虑什么情况的时候,把当前元素分配给哪一个序列会更优,使得序列最短。
对于当前准备去分配的元素 z1z1z1,以及 z1z1z1 后面一位元素 z2z2z2。
(1) 首先考虑对前面的贡献
- 当
x == y
时,上下两个序列给谁都无所谓 - 当
x == z1 && y != z1
时,很明显分配给 xxx 会更优。 - 当
y == z1 && x != z1
时,很明显分配给 yyy 会更优。
(2) 若上述条件均为达到就考虑对后面的贡献
- 当
x == z2 && y != z2
时,很明显分配给 yyy 会更优 - 当
y == z2 && x != z2
时,同理很明显分配给 xxx 会更优
最后一种情况:若x != z2 && y != z2
,以及其他的所有剩余情况,这时候就有讲究了。
看上去放到哪里都区别不大,但是我们想要最终的答案尽可能地小,也就是让元素尽可能合并,也就是:
a[i]a[i]a[i] 以后和 xxx 相同的元素(假设是 xxxxxx)尽量能和 xxx 合并,也就是以后 xxx 后面都不添加数。
a[i]a[i]a[i] 以后和 yyy 相同的元素(假设是 yyyyyy)尽量能和 yyy 合并, 也就是以后 yyy 后面都不添加数。
但是我们总归是要在 xxx 或者 yyy 后面选择一个数放进去,假设我们放到了 xxx 后面,这样也就断绝了后面的那个与 xxx 相同的元素 xxxxxx 与 xxx 合并的可能性。
所以我们应该取两个队列末尾元素:xxx 和 yyy 中 与它们相同的数 xxxxxx 或者 yyyyyy 的距离更近的那个队列。
我们假设是 yyy ,这样与 yyy 相同的数 yyyyyy 比与 xxx 相同的数 xxxxxx 距离更近,也就是一个一个来放的话,更先到达两个队列面前,是距离更短的那个数,也就意味着最终可以和 yyy 合并的可能性就更大,因此我们就把 a[i]a[i]a[i] 放到 xxx 的后面,让 yyy 去追逐合并的梦想 ~
应该很好理解,非常形象。
我们预处理一下下标 iii 的最近的下一个相同元素的下标 nex[i]\tt nex[i]nex[i] 就行了,如何实现具体看代码,很好理解。
总结一下就是:
若x != z2 && y != z2
,以及其他的所有剩余情况时:若nex[x] < nex[y]
,我们分配给 yyy 更优
若x != z2 && y != z2
,以及其他的所有剩余情况时:若nex[x] > nex[y]
,我们分配给 xxx 更优
所有条件按照我分析的时候的先后顺序if else
判断即可,因为越往前优先级越大,后面只是有合并的可能性,而前面是直接已经可以合并了。
最后简单实现一下就行了
Code
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
#include <unordered_map>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
typedef int itn;
const int N = 5e5 + 7, M = 6e6 + 7, mod = 1e9 + 7;
const ll INF = 1e18 + 7;int n, m, t, k;
itn a[N], b[N];
vector<int> v[N];
int nex[N];void solve()
{int ans = 0;scanf("%d", &n);for(int i = 1; i <= n; ++ i) {scanf("%d", &a[i]);v[a[i]].push_back(i);}for(int i = 1; i <= n; ++ i)nex[i] = n + 1;for(int i = 1; i <= n; ++ i) {for(int j = 0; j < (int)v[i].size() - 1; ++ j) {nex[v[i][j]] = v[i][j + 1];}}int x = 0, y = 0, nex_x = n + 1, nex_y = n + 1;for(int i = 1; i <= n; ++ i) {int z1 = a[i], z2 = a[i + 1];if(z1 == x) {nex_x = nex[i];}else if(z1 == y) {nex_y = nex[i];}else {ans ++ ;if(z2 == x && z2 != y) {y = z1;nex_y = nex[i];}else if(z2 == y && z2 != x) {x = z1;nex_x = nex[i];}else {if(nex_x < nex_y) {y = z1;nex_y = nex[i];}else {x = z1;nex_x = nex[i];}}}}printf("%d\n", ans);
}int main()
{solve();return 0;
}
E - Continuous City
Problem 1479C - Continuous City
定义中心图为:
有 nnn 个点,编号为 111 ~ nnn 。以及 mmm 条有向边。每一条有向边上都有一个正整数权值,并且这 mmm 条路都是从编号小的指向编号大的(意味着每次走都会朝着中心 nnn 进发)。并且对于任意两个不同的点,他们之间最多只有一条有向边。
定义 (L,R)(L,R)(L,R) 连续图为既满足中心图,又满足下述两个条件的有向图:
- 所有的从 111 到 nnn 的简单路径的长度 len∈[L,R]len\in[L,R]len∈[L,R]。
- 对于任意的 ddd ,L≤d≤RL\le d\le RL≤d≤R,均恰好存在一条且仅有一条从 111 到 nnn 的简单路径的长度等于 ddd。
仅给定 LLL 和 RRR,请问你能否构造一个符合题意且点数 nnn 不超过 32 的 (L,R)(L,R)(L,R) 连续图,如果不能,输出 NO
,否则输出 YES
并输出该图的 nnn 和 mmm (点数与边数),并输出 mmm 条边的情况(对于每条边,输出 x,y,zx,y,zx,y,z 表示第 iii 条边从 xxx 到 yyy 边长为 zzz)
Solution
今天下午(2/10)一定更…
Codeforces Round #700 (Div. 2) A ~ E ,6题全,超高质量良心题解【每日亿题】2021/2/8相关推荐
- Codeforces Round #700 (Div. 2) D2 Painting the Array II(最通俗易懂的贪心策略讲解)看不懂来打我 ~
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 整场比赛的A ~ E 6题全,全部题目超高质量题解链接: Codeforces Round #700 ...
- Codeforces Round #700 (Div. 1Div. 2)
Codeforces Round #700 (Div. 1&&Div. 2) 题号 题目 知识点 A Yet Another String Game 签到 B The Great He ...
- Codeforces Round #700 (Div. 2)A~D2解题报告
Codeforces Round #700 (Div. 2)A~D2解题报告 A Yet Another String Game 原题链接 http://codeforces.com/contest/ ...
- Codeforces Round 700 (Div. 2) B题 英雄杀怪兽
Codeforces Round 700 (Div. 2) B题 链接: https://codeforces.com/contest/1480/problem/B 大致意思: n组数据,每组数据的第 ...
- Codeforces Round #701 (Div. 2) A ~ F ,6题全,超高质量良心题解【每日亿题】2021/2/13
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 A - Add and Divide B - Replace and Keep Sorted C ...
- Codeforces Round #699 (Div. 2) (A ~ F)6题全,超高质量良心题解【每日亿题】2021/2/6
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Codeforces Round #699 (Div. 2) (A.B.C)[每日亿题]2021/2/ ...
- Codeforces Round #700 (Div. 2)全部题解
题目链接:https://codeforces.com/contest/1480 文章目录 A.Yet Another String Game B.The Great Hero C.Searching ...
- Codeforces Round #700 (Div. 1) C. Continuous City 构造 + 二进制
传送门 文章目录 题意: 思路: 题意: 构造一个图,使其从111到nnn的路径的长度与[L,R][L,R][L,R]中某个值一一对应,不能有两条路径长度一样,且每个值都必须出现一次,每两个点之间只能 ...
- Codeforces Round #700 (Div. 2) D1 D2. Painting the Array 思维
link 题意: 给一个数组,让你从头开始选出一些数放在AAA数组中,剩下的放在BBB数组中,且是有序选择,让后把两个数组中相邻且相等的元素合并. D1: 使合并后Len(A)+Len(B)Len(A ...
最新文章
- Windows Server入门系列38 访问网络共享
- IDEA VS 快捷键 大全
- html解决空格显示问题
- Scala可变集合:Queue增加和移除元素
- C++ cin.putback()输入【已知行数】但【未知每行数字个数】的思路
- Flutter之实战InheritedWidget详解
- verp中的Viewable objects
- openjtag openocd libftd2xx
- 东芝服务器报错误代码维修,实战维修 东芝复印机故障维修详解
- 联想台式计算机 不启动u盘,联想电脑不能u盘启动怎么办
- 做了一个iGoogle新闻Gardget
- Open JDK patched with font fix
- vuex报错TypeError: sub is not a function
- 一个JAVA小虾米初入江湖
- 太空探测器 java_宇宙究竟有多大?这个探测器或将告诉你答案
- linux网络测试工具
- 批处理为win7桌面添加计算机图标,win7桌面图标不见了图文解决方案
- origin导出矢量图变色,怎么办?
- Python下载网易云音乐(云音乐飙升榜)
- 【Android开发】
热门文章
- 可微分的「OpenCV」:这是基于PyTorch的可微计算机视觉库
- 求最小Hamming距离的DNA序列
- 最全的MAC端截图工具推荐,寻找适合自己的截图工具
- Kubernetes-基于EFK进行统一的日志管理
- 其实win10要比win7的安全性强很多
- 使用maven profile 构建不同环境引用不同的值
- 烂泥:ubuntu 14.04搭建Open***服务器
- (备忘)Java数据类型中String、Integer、int相互间的转换
- [转]ASP.NET页面生命周期描述
- pandas dataframe 表头_python_库_pandas