整理的算法模板合集: 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) 考虑对前面的贡献

  1. x == y 时,上下两个序列都无所谓。
  2. x == z1 && y != z1 时,很明显分配给 yyy 会更优。
  3. y == z1 && x != z1 时,很明显分配给 xxx 会更优。

(2) 考虑对后面的贡献

  1. x == z2 && y != z2 时,很明显分配给 xxx 会更优,因为可能 z1z1z1 可以填上这个合并的漏洞,填不上的话,就算了,但会更优
  2. y == z2 && x != z2 时,同理很明显分配给 yyy 会更优。
  3. 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) 首先考虑对前面的贡献

  1. x == y 时,上下两个序列给谁都无所谓
  2. x == z1 && y != z1 时,很明显分配给 xxx 会更优。
  3. y == z1 && x != z1 时,很明显分配给 yyy 会更优。

(2) 若上述条件均为达到就考虑对后面的贡献

  1. x == z2 && y != z2 时,很明显分配给 yyy 会更优
  2. 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) 连续图为既满足中心图,又满足下述两个条件的有向图:

  1. 所有的从 111 到 nnn 的简单路径的长度 len∈[L,R]len\in[L,R]len∈[L,R]。
  2. 对于任意的 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相关推荐

  1. Codeforces Round #700 (Div. 2) D2 Painting the Array II(最通俗易懂的贪心策略讲解)看不懂来打我 ~

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 整场比赛的A ~ E 6题全,全部题目超高质量题解链接: Codeforces Round #700 ...

  2. Codeforces Round #700 (Div. 1Div. 2)

    Codeforces Round #700 (Div. 1&&Div. 2) 题号 题目 知识点 A Yet Another String Game 签到 B The Great He ...

  3. Codeforces Round #700 (Div. 2)A~D2解题报告

    Codeforces Round #700 (Div. 2)A~D2解题报告 A Yet Another String Game 原题链接 http://codeforces.com/contest/ ...

  4. Codeforces Round 700 (Div. 2) B题 英雄杀怪兽

    Codeforces Round 700 (Div. 2) B题 链接: https://codeforces.com/contest/1480/problem/B 大致意思: n组数据,每组数据的第 ...

  5. Codeforces Round #701 (Div. 2) A ~ F ,6题全,超高质量良心题解【每日亿题】2021/2/13

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 A - Add and Divide B - Replace and Keep Sorted C ...

  6. Codeforces Round #699 (Div. 2) (A ~ F)6题全,超高质量良心题解【每日亿题】2021/2/6

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Codeforces Round #699 (Div. 2) (A.B.C)[每日亿题]2021/2/ ...

  7. Codeforces Round #700 (Div. 2)全部题解

    题目链接:https://codeforces.com/contest/1480 文章目录 A.Yet Another String Game B.The Great Hero C.Searching ...

  8. Codeforces Round #700 (Div. 1) C. Continuous City 构造 + 二进制

    传送门 文章目录 题意: 思路: 题意: 构造一个图,使其从111到nnn的路径的长度与[L,R][L,R][L,R]中某个值一一对应,不能有两条路径长度一样,且每个值都必须出现一次,每两个点之间只能 ...

  9. Codeforces Round #700 (Div. 2) D1 D2. Painting the Array 思维

    link 题意: 给一个数组,让你从头开始选出一些数放在AAA数组中,剩下的放在BBB数组中,且是有序选择,让后把两个数组中相邻且相等的元素合并. D1: 使合并后Len(A)+Len(B)Len(A ...

最新文章

  1. Windows Server入门系列38 访问网络共享
  2. IDEA VS 快捷键 大全
  3. html解决空格显示问题
  4. Scala可变集合:Queue增加和移除元素
  5. C++ cin.putback()输入【已知行数】但【未知每行数字个数】的思路
  6. Flutter之实战InheritedWidget详解
  7. verp中的Viewable objects
  8. openjtag openocd libftd2xx
  9. 东芝服务器报错误代码维修,实战维修 东芝复印机故障维修详解
  10. 联想台式计算机 不启动u盘,联想电脑不能u盘启动怎么办
  11. 做了一个iGoogle新闻Gardget
  12. Open JDK patched with font fix
  13. vuex报错TypeError: sub is not a function
  14. 一个JAVA小虾米初入江湖
  15. 太空探测器 java_宇宙究竟有多大?这个探测器或将告诉你答案
  16. linux网络测试工具
  17. 批处理为win7桌面添加计算机图标,win7桌面图标不见了图文解决方案
  18. origin导出矢量图变色,怎么办?
  19. Python下载网易云音乐(云音乐飙升榜)
  20. 【Android开发】

热门文章

  1. 可微分的「OpenCV」:这是基于PyTorch的可微计算机视觉库
  2. 求最小Hamming距离的DNA序列
  3. 最全的MAC端截图工具推荐,寻找适合自己的截图工具
  4. Kubernetes-基于EFK进行统一的日志管理
  5. 其实win10要比win7的安全性强很多
  6. 使用maven profile 构建不同环境引用不同的值
  7. 烂泥:ubuntu 14.04搭建Open***服务器
  8. (备忘)Java数据类型中String、Integer、int相互间的转换
  9. [转]ASP.NET页面生命周期描述
  10. pandas dataframe 表头_python_库_pandas