程序设计方法与实践第一周心得感受(BIT小学期)
说在前面的话:
如果本博客能够对后来的学弟学妹们或者网上的各位朋友们有那么一点点帮助的话,那么自己当初熬夜debug的价值也就不局限于那么一两个测试用例了,这真的很让人开心;
在这里还是要先感谢之前的学长认认真真写的csdn博客千里之码的博客_CSDN博客-BIT2021小学期程序设计实践领域博主,也要感谢lexue
讨论区各位大佬无私分享自己的思路,加油捏各位,各位都不是一个人!!!
第一周题解及感受(上)
第一题:达拉蹦巴的舞会
先说过程,提交了五次,两次是因为在乐学选了
gcc
提交g++
代码,第一次是因为没看清题目给出的要求\(1<n<10^{18}\)然后回去修改,第四次是long long
结果把int main()
中的int
也替换成了long long
,最后一次提交成功;
说下自己思路:
- 一开始认为每只小白鼠只能喝一桶酒,发现用例对不上;
- 后来结合题意认为每只小白鼠可以喝混合起来的酒来检测;
- 我们开始这样想,每一只小白鼠都有两种状态,生和死,他们的组合种数应该能大于酒桶数才能符合条件,比如
生死 生生 死生 死死
共四种,凭这四种状态我们最多就能区分4桶酒,当然3桶,2桶都可以,但题目要求的是老鼠要少,这就决定了2桶用一个小老鼠就能区分,生 死
,进一步,我们不难想到这是一个十进制转化成二进制的问题,
很显然我们所求的就是二进制的位数;
第二题:摘桃子
考虑策略决策问题,在这里决策顺序很重要;这里自己主要这样做:
输入处理数据
对输入的天数相同,及同一天成熟的桃子树当作一颗树来处理;
对输入的桃子数成熟天数数组以及桃子树木果实数组同时按照天数排序,从小到大;
对数组中的数据分类讨论
先处理前一天的桃子;
处理今天的桃子;
处理之后吃不完的桃子;
输出总桃子数
这个就是要把处理桃子的顺序理清,很多人说这也是一个贪心的决策问题,为了实现最优化我们必须如何充分利用?的日期,还要考虑一天?能采摘的数目和自己的精力,再处理前一天和今天的?时实际上要考虑到自己处理的精力;
第三题:解密游戏
按位异或方法和DFS来做,自己是没有太理解大佬们的异或方法;自己是纯纯普通方法;
关于dfs
自己写了一个短短的博客,主要是做了两个gif
,帮助自己理解什么是DFS
关于题解,在csdn
上有写的很好的思路,这里说一下自己的:
对于
dfs
我们习惯于考虑完一种情况再去考虑另一种,所以在枚举时需要注意最初的枚举角度,我们决定按照遍历的角度来思考,按一行一行来对灯进行操作:首先是思考第一行操作情况,我们的深搜就发生在第一行里面,递归第一行中每一个灯按或不按的情况;
在递归的基态中,再处理第一行以后的行的灯的情况即可,若最后一行灯还有灯亮,说明该方法道路不通(另外说一句:其实最后一行灯亮我们也是可能通过按某些操作去关掉它们的,但是这样就不再符合我们最少按下次数的要求了,要知道,一个灯按两次等于没按,所以我们对每个灯都不允许重复按)
第四题:北湖挖坑
很多方法,主要还是注意读入时处理还是读入后在处理;
此题我们边读入边处理回好很多,这样保证复杂度是\(O(n)\);
第五题:北湖深坑(接雨水问题)
本题用动态规划以及单调递减栈方法均可成功通过(\(O(n)\)复杂度即可成功,两者都是可行的)
如果用暴力枚举复杂度必然是\(O(n^2)\),对于\(1e5\)的数据量我们自然排除这种方法;
然而现实情况不太一样,即使使用了上面的动态规划方法或者单调栈的方法依然过不了;
原因如下(总的来说还是对cpp
不够熟悉):
- 不能用
cin
读入,要用scanf
;两者的读入速度决定了上面拿两个用例能否过去; - 参考博客:探寻C++最快的读取文件的方案 (byvoid.com)
说一下两种方法:
动态规划
先读入一遍,再分别左遍历和右遍历一次记录每一个点的左边最高点和右边最高点;
最后遍历一遍,取两边最高点中的最低点减去当前点高度,求和得出结果;
单调递减栈
在把元素读入数组的同时,另外创建一个栈储存数组的中之前出现过的且递减的元素
但凡读入递减后的第一个递增元素就开始处理填坑(吐出当前栈顶元素作为?底部)
先填最近的坑,也即该递增元素和目前栈顶元素围成的坑(填完之后继续吐出栈顶元素);
再循环填坑,直到没有坑可填再读入新元素(没有坑有两种情况:当前栈顶元素大于读入的元素、栈为空,当然当遇到前者情况时我们也需要把当前元素填入栈中,因为之前?填满的同时我们又符合递减条件了)
拓展:网上甚至还有人写了双指针的操作,有人说这个方法时最妙的;
第一周题解及感受(个人猜测保密用例的小tips)(下)
前言
在VScode调试时不能有中文路径……
这周里好好反思了下自己不能及时做出题目……
- 对于之前的自己,每一道题几乎都要花费两个小时以上,除了写出程序还要花大量时间debug;
- 写题不能很高效的原因,开始没有找到方向,上来就写,对多情况束手无策;
- 写条件判断时没有好好想背后原因,贪快,急;
- 几乎就是上面这两点导致自己花很多时间在调试上面:就比如第一周的肥宅快乐串和括号匹配,前者是没有考虑好判断条件,在只有两个字符不匹配的情况下单独认为只要一个字符等于另外一个位置上的原字符即可,而没有认真考虑是否符合两者互换的条件;在括号匹配中,自己忽略了
cin
和scanf
一样,同样都不会读入'\n'这一点,导致没有压线过👊昨晚十二点截止的括号匹配;以上两者都是一堆正确的用例中错红了两个保密用例,确实很难受,不过我们也可以仔细观察保密用例中的条件,可以这样去改一般(个人经验,求指正😭);TLE : 超时和内存溢出几乎差不多,只要看题时有好好考虑算法复杂度(数据数目的上限和遍历次数)几乎就能少走一点弯路(比如排除某些暴力枚举);
WA : 这个一般是某些方面没考虑全面,在重新阅读自己程序建议挖掘各种可能异常,不断反问***难自己一般可以发现bug;
格式错误:这个通常在正常用例就能看出来或者自己编一两组数据基本能发现;
别的 : 观察内存、观察用时,如果出现两者几乎差不多的,那就说明数据规模是比较相似的,我们可以根据这些关系去猜测哪一方的问题,用时0.998或者0.999的老实回去改改算法或者大数据量读入时的
cin
改为scanf
又或者自己开大一点数组(这些应该在读题目时就应该做好);另外的经验
- 布置题目之后要尽快做,感觉其实每道题都值得用心去想,得花时间去磨合,不要赶
ddl
- 从基本的用例先写一个小小的demo开始,不求上来就考虑全面,先实现一个基本的demo当对题目有简单了解(写demo的时候就可以观察主要循环放在哪里了)
- 善于利用讨论区搜索功能,大家都在这集思广益,并不是一个人捏;
正文
第六题:A+B(I)
这道题主要考查异或的性质,两个二进制的数相加,我们最主要的还是考虑格式,自己的思路大概这样
第七题:A+B(II)
这道题是为数不多的一次提交就全部AC的题目,但遗憾的是还是过了应该提交的时间了,说句实在话,这道题最考验人的地方就是不断修改输出的格式,考虑各种情况下可能的格式是什么,需要花费大量的时间投入其中;说下自己思路
第八题:改作文
-
忽略很久之前的点,
scanf
和cin
都是会忽略空格读入的,所以我们在读入有空格的一句话时要注意不能直接cin >> str;
或者scanf("%s",&str);
这样是读不进空格之后的内容的;正确的应该是逐字符scanf
:while (scanf("%c",&str[i])!=EOF) { i++; }
-
VScode
调试时如果要单独查看某个数组时记得把该数组的内存开得小一点,不然调试的时候不能加载处里面的真实情况,最后要记得改回来; -
还有就是在终端模拟文件读到
EOF
我们的方法是光标停留在终端时按Crtl+Z,此时可能会出现光标不在终端的情况,此时记得重新返回终端窗口在^Z
之后按回车即可;
第九题:肥宅快乐串
思路:
第十题:括号匹配
用栈或用数组做均可,这道题不是难题,就是注意scanf
数字后马上scanf
某个字符大概率会输入一个换行符,所以我们注意把回车吃掉就好;
有大佬写得更好的,比如👆👆