Educational Codeforces Round 114总结

绪论

https://codeforces.com/contest/1574/
以前想要打CF,总是觉得没有时间,要做这个,要做那个,现在时间充裕了一些,想要多打一些CF,但是光打比赛不总结是没有什么帮助的,这是我从以前的ACM训练中吸取的惨痛教训。从这篇文章开始准备好好总结一些比赛心得。

这场比赛是for div2的,因此对我来讲有些难度,我发挥的不是很好,然后理所当然就掉分了(掉了50+,哭哭)

A

解题思路

要求构造正确的括号组合,即每一个左括号有一个相应匹配的右括号,要求给定括号对数n,输出其n种组合方式。

刚开始思考了一下将左括号看作1,右括号看作-1,任何时刻整个表达式的和为非负数:要求每出现一个右括号的时候都有其对应的左括号。通过
这种方式进行构造。

但是很快,我发现其中的递推关系:
一对括号:()
两对括号:()()、(())
三对括号:()()()、(())()、((()))

我们不难发现,对n对括号的情况,其前2n-2个位置可以是n-1对括号的所有情况,然后最后再加一对括号
但是有一种情况不能由n-1对括号得来:最后两个是))的时候,简单起见,前n个都是(,后n个都是)显然是一个解。

通过这种构造方法:Tn=Tn−1+1T_n = T_{n-1} + 1Tn=Tn1+1T1=1T_1 = 1T1=1,我们总能够造出n个解。因为n最多是50,我们只需要首先通过递推构造出所有的解,然后直接输出即可。

但是显然n对括号不止n种解(当时比赛的时候心中有这个疑惑,但是没有时间去仔细思考):
对三对括号而言,还有一种解:()(())。

AC代码

// Copyright(C), Edward-Elric233
// Author: Edward-Elric233
// Version: 1.0
// Date: 2021/9/20
// Description: #include <vector>
#include <string>
#include <iostream>using namespace std;const int MAXN = 51;
vector<vector<string>> ans;int main() {ios::sync_with_stdio(false);ans.push_back(vector<string>());ans.push_back(vector<string>());ans[1].push_back("()");for (int i = 2; i < MAXN; ++i) {ans.push_back(ans[i - 1]);for (auto &s :ans[i]) {s.append("()");}ans[i].push_back(string(i, '(') + string(i, ')'));}int T;cin >> T;while (T--) {int n;cin >> n;for (int i = 0; i < n; ++i) {cout << ans[n][i] << "\n";}}return 0;
}

B

解题思路

给定a、b、c个数的A、B、C,要求其相邻两个重复的次数为m次
我当时初步的想法是求出最小重复次数和最大重复次数,如果m在两者之间则YES,否则则NO。
最大重复次数显然是所有的A都出现完了后B再出现,然后C再出现,因为都放在一起出现一个重复的代价是1个字母(除了第一个),但是一旦A结束重复,还想A出现相邻的重复,又要消耗一个没有意义的字母作为第一个。
在求最小重复次数的时候我犯了错导致WA了一发。当时想着,假设a<=b<=ca<=b<=ca<=b<=c,让A、B、C循环出现,肯定先将A消耗完,然后B、C再重复出现,最后就只剩下C不得不重复,因此重复的个数是(c−a)−(b−a)−1=c−b−1(c-a)-(b-a)-1=c-b-1(ca)(ba)1=cb1
但是我忘记了,也有可能是A、B一起消耗C,这样重复的个数是c−b−a−1c-b-a-1cba1,显然比上面小。
但是有一个问题就是,如果a+b>ca+b>ca+b>c怎么办?这个时候我们可以采取以下策略:首先让A、B重复出现使得(a+b)(a+b)(a+b)每次减少2。因为当c−(a+b)c-(a+b)c(a+b)为1或者0的时候都没有重复,所以我们总能够通过这种策略不出现重复,因此最小重复次数为max(c−a−b−1,0)max(c-a-b-1,0)max(cab1,0)

上面的思路最后是AC的。但是不免还有一个疑问?为什么我们能够保证在minminminmaxmaxmax之间的重复次数都能够出现?
也就是说我们可以采取一种策略,对m个重复的排列C1C_1C1,通过删除插入将其转换成m-1个重复的排列C2C_2C2

这种策略如下:我们可以将某个重复中的元素X取出,则重复变为m-1,剩下我们要做的就是将X再插入排列,我们只要插入和其左右都不同,且左右不同的一个位置。因为数据保证A、B、C都至少出现一次,且更少重复的排列是存在的,我们应该总能够找到这样一个位置。

好吧,我承认我有些证明不过来了,不过大概就是上面那样。

AC代码

// Copyright(C), Edward-Elric233
// Author: Edward-Elric233
// Version: 1.0
// Date: 2021/9/20
// Description: #include <iostream>using namespace std;int main() {ios::sync_with_stdio(false);int T, a, b, c, m;cin >> T;while (T--) {cin >> a >> b >> c >> m;if (a > c) std::swap(a, c);if (b > c) std::swap(b, c);if (a > b) std::swap(a, b);int min = std::max(c - b - a - 1, 0);int max = a + b + c - 3;if (m >= min && m <= max) {cout << "YES\n";} else {cout << "NO\n";}}return 0;
}

C

这道题比赛的时候没做出来,但是我的思路是对的,只是在实现的时候当时已经十二点了,脑袋已经不转了,糊涂了。也有一方面的原因是自己有一些想当然:对于一个数组a0,a1,a2,...,an−1a_0,a_1,a_2,...,a_{n-1}a0,a1,a2,...,an1,和一个区间[a,b][a,b][a,b],我认为如果a0<ba_0 < ba0<ban−1>aa_{n-1} > aan1>a则一定有元素在[a,b][a,b][a,b]区间内。。。现在发现这个错误后就AC了,呜呜呜,如果这道题做出来说不定我都上分了。

解题思路

题目的意思是,有一个数组,其和为sum,要求ai+c1⩾x&sum−ai+c2⩾ya_i + c_1 \geqslant x \And sum-a_i+c_2\geqslant yai+c1x&sumai+c2y,求最小的c1+c2c_1+c_2c1+c2
通过对问题的分析,进行分类讨论(看起来很复杂的问题有可能通过分类讨论变得清晰起来)

  1. sum⩽ysum \leqslant ysumy
    这个时候无论取出哪个元素用来和x比较,都会导致sum更小,因此总需要花钱,
    1.1. sum⩽xsum \leqslant xsumx
    说明任何一个元素都小于x,那么我们需要的钱为x−ai+y−(sum−ai)=x+y−sumx-a_i+y-(sum-a_i)=x+y-sumxai+y(sumai)=x+ysum。这真是令人振奋的消息,也就是说在这种情况下我们无论取哪个元素花费都是一样的
    1.2。 sum>xsum > xsum>x
    这个时候问题又变得复杂起来了,如果里面小于等于x的元素,花费和上面一样为y−sum+xy-sum+xysum+x,对于其中大于x的元素,需要的钱为y−sum+aiy-sum+a_iysum+ai,也就是说aia_iai越小越好,但还是大于xxx
    综上,当sum⩽ysum \leqslant ysumy时,如果该数组中存在一个小于等于x的元素,最优解就为y−sum+xy-sum+xysum+x,如果全部都大于x,最优解为y−sum+min(ai)y-sum+min({a_i})ysum+min(ai),为了方便做到这一点,我们不妨对数组进行排序,通过判断a0a_0a0与x的大小判断解为y−sum+xy-sum+xysum+x还是y−sum+a0y-sum+a_0ysum+a0
  2. sum>ysum>ysum>y
    这个时候的情形更加复杂,因为存在可能不花钱的状况。因此,我们不妨再对这种情况进行分类:
    2.1. sum−ai⩾y&ai⩾xsum-a_i\geqslant y \And a_i \geqslant xsumaiy&aix
    这种情况下我们不用付钱,要求∃ai,x⩽ai⩽sum−y\exists a_i,x\leqslant a_i\leqslant sum-yai,xaisumy
    2.2. sum−ai<y&ai⩾xsum-a_i < y \And a_i \geqslant xsumai<y&aix
    这种情况要付钱y−sum+aiy-sum+a_iysum+ai,要求∃ai,ai⩾x&ai>sum−y\exists a_i,a_i\geqslant x \And a_i > sum - yai,aix&ai>sumy
    2.3. sum−ai⩾y&ai<xsum-a_i\geqslant y \And a_i < xsumaiy&ai<x
    这种情况要付钱x−aix-a_ixai,要求∃ai,ai<x&ai⩽sum−y\exists a_i,a_i < x \And a_i \leqslant sum - yai,ai<x&aisumy
    2.4. sum−ai<y&ai<xsum-a_i<y \And a_i <xsumai<y&ai<x
    这种情况要付钱y−sum+ai+x−ai=x+y−sumy-sum+a_i+x-a_i=x+y-sumysum+ai+xai=x+ysum,要求∃ai,sum−y<ai<x\exists a_i,sum-y<a_i< xai,sumy<ai<x
    我们发现,在这种情况下另一个重要的量sum−ysum-ysumy经常出现,因此我们另z=sum−yz=sum-yz=sumy,然后将x和z之间的关系进行分类讨论。
    2.5.x⩽zx\leqslant zxz
    这个时候2.4不可能发生,只剩下了三种情况,我们可以分别对三种情况进行快速求解,对于满足2.1的aia_iaians=0ans=0ans=0,对于满足2.2的aia_iai,我们要找到满足ai>za_i>zai>z的最小aia_iaians=ai−zans=a_i-zans=aiz,对于满足2.3的aia_iai,我们要找到满足ai<xa_i<xai<x的最大aia_iaians=x−aians=x-a_ians=xai,即这个情况的解为三种解的最小值
    2.6. x>zx > zx>z
    这个时候2.1不可能发生,剩下三种情况的讨论与2.5相同
    上面的求值在一个排好序的数组中都可以使用lower_boundlower\_boundlower_boundupper_boundupper\_boundupper_bound函数快速解决

每次查询的复杂度为O(logn)O(log_n)O(logn),总复杂度为O((n+m)logn)O((n+m)log_n)O((n+m)logn),前者是排序的复杂度,这对2e52e52e5的复杂度是可以接受的

实现上面的程序需要对二分查找非常熟悉,但是自己实现的二分查找非常容易出现Bug,使用STL中的lower_boundlower\_boundlower_boundupper_boundupper\_boundupper_bound就成了不二之选,这要求我们对这两个函数非常熟悉。基本的用法很简单,lower_boundlower\_boundlower_bound返回大于等于关键字的第一个迭代器,upper_boundupper\_boundupper_bound返回大于关键字的第一个迭代器,两者之间的范围就是等于关键字的范围,如果要访问元素一定要判断是否等于尾后迭代器。如何求小于和小于等于有一个小技巧,对于小于,也就是大于等于的前一个元素,我们将lower_boundlower\_boundlower_bound向前移动一个就是最后一个小于关键字的元素,小于等于同理,不过我们需要注意的是要判断迭代器是否是开始迭代器,如果是开始迭代器则说明不存在小于或者小于等于的元素。

这个思路是我在比赛的时候想出来的,后来再看发现还是很复杂,惊叹自己当时竟然能够想这么多。不过比较可惜的是在判断2.1-2.4的时候我的脑袋已经糊涂了,导致最终没能AC。这也提醒我千里之堤毁于蚁穴,行百里半九十,对一个程序来说每一个细节都是致命的,可能平时很瞧不起,觉得很简单 ,但是他们其实是平等的,要对每一个小细节怀有敬畏之心。

AC代码

// Copyright(C), Edward-Elric233
// Author: Edward-Elric233
// Version: 1.0
// Date: 2021/9/20
// Description: #include <vector>
#include <array>
#include <iostream>
#include <algorithm>
#include <climits>using namespace std;constexpr int MAXN = 2e5 + 5;
using ll = long long;
array<ll, MAXN> a;
int n, m;
ll x, y, sum, ans, z;int main() {ios::sync_with_stdio(false);cin >> n;sum = 0;for (int i = 0; i < n; ++i) {cin >> a[i];sum += a[i];}auto begin = a.begin();auto end = a.begin() + n;std::sort(begin, end);cin >> m;while (m--) {ans = LONG_LONG_MAX;cin >> x >> y;if (sum <= y) {if (a[0] > x) {ans = y + a[0] - sum;} else {ans = y + x - sum;}} else {z = sum - y;if (x <= z) {if (a[0] > z) {ans = a[0] - z;} else if (a[n - 1] < x) {ans = x - a[n - 1];} else {ans = LONG_LONG_MAX;auto it1 = std::upper_bound(begin, end, z);if (it1 != end) {ans = std::min(ans, *it1 - z);}auto it2 = std::lower_bound(begin, end, x);if (it2 != end && *it2 <= z) {ans = 0;}if (it2 > begin) {--it2;ans = std::min(ans, x - *it2);}}} else {if (a[0] >= x) {ans = a[0] - z;} else if (a[n - 1] <= z) {ans = x - a[n - 1];} else {ans = LONG_LONG_MAX;auto it1 = std::lower_bound(begin, end, x);if (it1 != end) {ans = std::min(ans, *it1 - z);}auto it2 = std::upper_bound(begin, end, z);if (it2 != end && *it2 < x) {ans = std::min(ans, x - z);}if (it2 > a.begin()) {--it2;ans = std::min(ans, x - *it2);}}}}cout << ans << "\n";}return 0;
}

后面的题目我没有看,我发现做出来的人很少。也不准备去做,题目无穷无尽,不应该去追逐题目,而应该做一题会一题,从有限的题目中提升自己的思维能力。觉得做CF好像做智力游戏,也挺有意思的。至于数据结构、算法,可以刷紫书嘛。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383526.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UVA - 210:Concurrency Simulator

题目链接&#xff1a;https://vjudge.net/problem/UVA-210 题目分析 就是一道模拟题&#xff0c;但是细节有点多。 写代码两个小时&#xff0c;调试代码用了两天。。。很长时间不刷题了&#xff0c;这道虽然算法简单但是细节满满的题目对我来说是一个很好的热身。 尽量不要去…

UVA - 514:Rails

题目链接&#xff1a;https://vjudge.net/problem/UVA-514 题目分析 题目的意思是给一个栈输入一系列数据&#xff0c;在这个过程中可以出栈&#xff0c;看能否达到某个结果。 刚开始我觉得这个情况好多&#xff0c;因此不是用模拟&#xff0c;而应该观察结果本身。对于结果中…

UVA - 442:Matrix Chain Multiplication

题目链接&#xff1a;https://vjudge.net/problem/UVA-442 题目分析 题目的意思非常简单&#xff0c;就是给定一个矩阵乘法的表达式然后计算就可以了。随便写写 AC代码 #include <iostream> #include <deque> #include <vector> #include <string>…

leetcode869. 重新排序得到 2 的幂

题目连接&#xff1a;https://leetcode-cn.com/problems/reordered-power-of-2/ 题目分析 如果直接顺着题目的思路&#xff0c;得到数字n的全排列&#xff0c;然后再去判断其是不是2的幂是比较复杂的。 我们应该注意到&#xff0c;因为数字是可以随意排列的&#xff0c;因此所…

使用wireshark+ssh+tcpdump远程抓包

因为需要抓取远程服务器上的数据包&#xff0c;又不想使用tcpdump这种命令行工具进行&#xff08;用了wireshark后谁还愿意去看密密麻麻的命令行呢&#xff09;&#xff0c;所以在网上查找了一下使用wireshark远程抓包的方法&#xff0c;在这里记录一下。 原生支持 wireshark…

C++ Variadic Templates(可变参数模板)

本文参考侯捷老师的视频&#xff1a;https://www.youtube.com/watch?vTJIb9TGfDIw&listPL-X74YXt4LVYo_bk-jHMV5T3LHRYRbZoH 以及C primer第五版 相关内容。 可变参数模板函数 //递归的终止条件 void print() {} //Variadic Templates //一般用于递归处理 template <…

Ubuntu修复Fix Busybox Initramfs错误

今天早上我打开电脑&#xff0c;进入Ubuntu系统&#xff0c;结果黑屏了&#xff0c;屏幕显示&#xff1a; BusyBox v1.30.1 (Ubuntu 1:1.30.1-4ubuntu6.1) built-in shell (ash) Enter help for a list of built-in commands.(initramfs)然而我并不知道这个是什么意思&#x…

Leetcode第284场周赛

绪论 最近发现Leetcode每周的周赛难度挺适合我的&#xff0c;而且时间也比较友好&#xff08;不像Codeforces每次都是半夜&#xff09;。所以连续参加了三周的周赛。这次才想起来应该记录一下自己的参赛历程。一方面是总结经验&#xff0c;另一方面有了记录就更有动力去提升&a…

Leetcode第286场周赛

绪论 上周因为有事没有参加周赛&#xff0c;这周没有错过。这次周赛拿到了人生第一个AK&#xff0c;参加大大小小的比赛这么多次&#xff0c;从来没有AK过&#xff0c;泪目了。 感觉这次比赛的思维难度对我来讲稍高一些&#xff0c;前三道题就花了一个小时&#xff0c;而以往…

第287场周赛

绪论 虽然是上周日参加的比赛&#xff0c;但是这周没有怎么学习&#xff0c;每天就是玩耍。也导致对周赛的总结迟迟没有进行。想着再拖下去下次周赛都要开始了&#xff0c;在这里补一下。 这场比赛总体比上场简单一些&#xff0c;但是最后一道题因为忘记初始化类内变量导致调试…

第288场周赛

绪论 虽然没有AK&#xff0c;但是不知道为什么排名比以前AK了都靠前。可能是因为最后一道题有些难度&#xff0c;缩小了我和大佬之间的差距。最后一个小时写最后一道题&#xff0c;累死累活想了一个贪心遍历的算法&#xff0c;当时是一直RE&#xff0c;后来下来调了调又WA了。 …

Clion远程部署和运行

绪论 作为Clion的忠实粉丝&#xff0c;现在的我的几乎所有的coding都是通过Clion完成。因为需要在服务器上进行开发&#xff0c;又离不开Clion&#xff0c;就了解了如何通过Clion远程部署和开发。 主要是借鉴了博客&#xff1a;使用Clion优雅的完全远程自动同步和远程调试c。如…

C++ 单例模式 call_once : terminate called after throwing an instance of ‘std::system_error‘

在学习了C中可以使用call_once进行初始化资源后&#xff0c;我就想着写一个单例模板供以后使用。 template<typename T> class SingleTon {using Ptr std::shared_ptr<T>;static Ptr p;static std::once_flag flag;template<typename ...Args>static void …

C++读写锁造成死锁

C14支持std::shared_timed_mutex C17支持std::shared_mutex 前者相比后者支持的操作更多&#xff0c;但是后者相对性能更好。 使用std::lock_guard<std::shared_mutex>和std::unique_lock<std::shared_mutex>互斥访问使用std::shared_lock<std::shared_mutex…

每日一题:449. 序列化和反序列化二叉搜索树

题目分析 题目链接&#xff1a;449. 序列化和反序列化二叉搜索树 觉得序列化很简单&#xff0c;前序遍历、后序遍历、中序遍历、层序遍历等等。其中得到前序遍历和后序遍历是可以通过递归解法反序列化的&#xff0c;觉得这样子做有点复杂。就想着可不可以一次遍历。一次遍历的…

C++高效集合数据结构设计

绪论 在复杂算法实现过程中我们经常会需要一个高效的集合数据结构&#xff0c;支持常数级别的增、删、查&#xff0c;以及随机返回、遍历&#xff0c;最好还能够支持交集、并集、子集操作 哈希集合实现 大家可能很快想到unordered_set&#xff0c;unordered_set由于底层是哈…

C++ 工具函数库

在写一些大型项目的过程中经常需要一些工具函数&#xff0c;例如获取随机数、计时器、打印函数、重要常量&#xff08;如最大值&#xff09;、信号与槽等&#xff0c;由于每一个工程都自己手动实现一个实在是太傻&#xff0c;我将其总结放入一个文件中。 utils.h // Copyright…

muduo网络库使用入门

muduo网络库介绍 muduo网络库是陈硕大神开发的基于主从Reactor模式的&#xff0c;事件驱动的高性能网络库。 网络编程中有很多是事务性的工作&#xff0c;使用muduo网络库&#xff0c;用户只需要填上关键的业务逻辑代码&#xff0c;并将回调注册到框架中&#xff0c;就可以实…

C++ map/unordered_map元素类型std::pair<const key_type, mapped_type>陷阱

在开发的过程中需要遍历一个unordered_map然后把他的迭代器传给另一个对象&#xff1a; class A; class B { public:void deal(const std::pair<int, A>& item); }; std::unordered_map<int, A> mp; B b; for (auto &pr : mp) {b.deal(pr); }在我的项目中…

Ubuntu install ‘Bash to dock‘

绪论 在Ubuntu环境搭建这篇博客中记录了使用Dash To Dock来配置Ubuntu的菜单项&#xff0c;使得实现macOS一样的效果。为了配置新电脑的环境&#xff0c;我还是想安装这个软件。但是如今在Ubuntu Software中已经找不到这个软件了&#xff0c;我在网上借鉴了一些博客的经验才得…