做题进度,目前还剩:
- [ ] H(30pts,还没de出bug)
- [ ] J(还没做)
其他均已完成。
A. 裁纸刀
题目链接:https://www.lanqiao.cn/problems/2060/learning
经过观察可以发现不管怎么切,刀数都是一样的。因此直接给出答案:
1 | def solve(n, m): |
B. 寻找整数
题目链接:https://www.lanqiao.cn/problems/2131/learning
也就是说给了一堆模的方程,求这个数最小值。
最朴素的暴力跑 ( 左右) 三个小时肯定跑不完。最快的方法应该是逐步合并的CRT,但是这题通过简单优化暴力,也可以很快跑出来。
暴力的思路是,假设我们目前已经知道了一个同余方程
那么现在 最小肯定是 。
现在新加入一个同余方程,要求 也满足
假设这个是一定能被满足的(题意,所以无需判断无解的情况),新的模数 很显然是 。那我们暴力以 的步长,寻找下一个最小的同时满足前面两个方程的 ,因为是最小的,也就是新的 。这样我们就得到了新的
然后这样跳个50次就得到了答案。不会分析这个时间复杂度,但是很显然就是能很快跑出来的,毕竟这个 是一直在做lcm,指数级别增大的。
1 | import math |
C. 质因数个数
题目链接:https://www.lanqiao.cn/problems/2155/learning
最大运行时间 10s, 最大 1e16, 的算法应该可以过。
一开始想手写一个筛法,筛 以内的所有质数即可。但是马上MLE了,1e8的set
是存不下的应该,虽然算了下512MB可以存的下。然后直接分解质因数,对于质因数直接把全部因子都除掉,这样可以保证下一个能取模的数一定还是质数(更小的因子已经没了)。
1 | # 90 % |
这样写只有90分,还是T了一个点。需要继续优化,进一步的优化方案逐步如下。
① 必须注意Python中for .. range
比while
要快得多,因为for .. range
遍历底层是由C语言实现的。
这样优化后,本地测试,运行速度从 9s
可以优化到 7s
,那很好了。
1 | import os |
但是蓝桥杯的古董机好像还不够,还是会T一个点。
② 发现是因为引入math
库好像会慢一点点,去掉math
库就好了。现在可以A了。但是看时间有点极限。
1 | # 100 % |
③ 继续优化的话,就是对2特判,这样后面就只需要枚举奇数即可。下面是最后时间稳过的代码,本地运行从前面的9s
、7s
到3.5 s
。
1 | import os |
D. 矩形拼接
题目链接:https://www.lanqiao.cn/problems/2154/learning
很容易想到是那种史山模拟题,有一大堆if else。只能试图比较有条理的枚举。
我的思路是,首先任意选两块拼一起,最坏情况就是随便乱放的时候,会有8条边。
一种一定能达到的更优情况,是两条边共线的情况:

这种情况可以视为一个大矩形有一个缺口。

不妨在假设第三个矩形一定填在这个叠起来的(最多6边)形的某一个边上。这样就能直接枚举了。(我三个矩形枚举所有可能排列)。
这样,每个询问,搜索的次数是 ,最后的时间复杂度是可以接受的。
1 | try: |
E. 消除游戏
题目链接:https://www.lanqiao.cn/problems/2127/learning
纯模拟题,感觉最简单的写法就是直接 模拟一个链表,初始遍历一遍找到可以删的节点,然后每次删除时把这个节点左边、右边、左边的左边、右边的右边,4个节点都纳入考虑范围。(然后就和下面的代码一样模拟成构思了,写了快一百多行)
1 | import os |
F. 重新排序
题目链接:https://www.lanqiao.cn/problems/2128/learning
(感觉是这场最简单的一题。)
第 个元素,对最终和的贡献,取决于它处于几个区间内。如果处于 个区间内,那最终贡献就是
我们可以 预处理出来第 个位置处于区间个数的 。(这种区间叠加,直接用差分即可)
对于越大的 ,很显然匹配越大的 ,会使得结果最大。
1 | import os |
G. 全排列的价值
题目链接:https://www.lanqiao.cn/problems/2137/learning
和前面一题一样,从贡献的角度切入。数 ,在排列中对这个排列价值的贡献就是它后面所有比它大的数的个数。全排列中,对于数 ( ),会有多少次机会也就是有多少个排列,会排在 后面?很显然是
也就是说所,数 对最后我们要输出的答案的贡献是
最后总的答案是
然后需要注意,如果不写逆元,就需要特判一下两个 2 因子消掉即可。
1 | import os |
H. 最长不下降子序列
链接:https://www.lanqiao.cn/problems/2088/learning
I. 最优清零方案
链接:https://www.lanqiao.cn/problems/2138/learning
很显然可以发现,我们只要先尽可能地 个连续消掉,随便做,消到没办法再消,然后对剩下的逐个消除即可。
因此直接 遍历一遍,遍历到 时,对 消掉 即可。正确性是有保证的。
下面是暴力的写法,时间复杂度最坏 .
1 | import os |
虽然这题时间复杂度非常坏,最坏会到 ,但是蓝桥杯官网上测试这段代码,是直接100%通过……
但是还是看下怎么优化。
上述的步骤,说简单就是对于 ,我们对 这一个区间,全部减去区间中最小的 ,然后 就可以跳到 了,继续下一步即可,可以看出主要的时间复杂度的问题都在寻找这个最小的 上和区间减法上了,因为朴素的做法中,一定要遍历 个数才能找到最小的,在不打标记的情况下,区间减法也是要一个个减掉的。所以很自然会想到用线段树来实现区间减法和最小值寻找,这样时间复杂度就变成了 , 对的。
除此之外我感觉也可以用双端队列来做。但是写起来可能比线段树更难调,那不如直接线段树了。但是线段树会狠狠卡常,必须尽可能不搜就不搜。
1 | import sys |