20210817K 复盘
都看出来做法了,但是终究没有拿到分
s2oj559 A.魔力
发现我们只让所有字符出现次数相同即可
考虑到若 \(suma[r] - suma[l-1] = sumb[r] - sumb[l-1]\),
则 \(suma[r] - sumb[r] = suma[l-1]- sumb[l-1]\)
这样,将 52 种字符开一个桶,桶的前后做差分构成一个 "特征序列",查找前面有多少个等于这个序列的位置即可
将 vector 或者 valarray 扔进去会超时,考虑 hash 这个序列
然后写 hash,遂被卡 + 超时...100 -> 80 -> 75
需要注意的是:
- 直接自然溢出啥事没有,使用模数多半超时且被卡
- unsigned long long 配合 unordered_map 开桶要比开 multiset 再 count 快无数倍。不知道为什么。
ywk 实现了一个巧妙的随机化方法:
- 考虑到,若 \([l,\ r]\) 是一个满足要求的子串,那么对于它们的桶来说,一定是:每个桶都差相等的次数,画在条形图上相当于是砍掉了最底下的几层
所以给每一种不同的字符分配一个随机键值,令一个模数 P 为所有不同字符的键值和
然后实时维护桶内所有字母的键值和,让他 %P,这样就相当于是构造了一种方法,使得两个 "每个桶都差相等次数" 的数对 hash 值相同,这样再开 unordered_map 记录即可
代码简单,稍微有点看脸
s2oj560. B.粒子
考场上想一想,哦,不会做,只会枚举。又想一想,哦,这可以二分,\(k\) 很小,差不多就过了
然后写写写,测样例无锅。考完评测发现挂了,100 -> 25
,莫名其妙 re,应该是访问负下标了
写实数二分的时候一定要注意的:
- 习惯性
#define double long double
。实数精度误差在二分过程中是很致命的,精度不够,可能左右指针永远都不能到达相差 eps 之内,然后就 t 了。 - check 一定要简单,一定不能写复杂,不能想复杂,尝试使用最简单不易错的方式 check,由于二分过程玄学,逻辑稍微复杂就很可能导致玄学锅,死活不明真相,浪费时间
s2oj561. C.六
考场思考出来一种状压方法,压 \(f[i][S]\) 表示,填长度为 i 的序列,每一种质因子出现情况(0,1,>1 次)为 \(S\)
然后根据这个用剩下能用的质因子 dfs 出来一个因数然后转移上去方案数。答案取 \(\sum f[i][*]\)
写写写,到 11:40 左右测样例发现过不去,怪了。然后查错,没查出来,最后无果。可能是做法假了?至今不明
wgx 使用 __int128 递归求解(__int128 可以换成 bitset):
我们将 n 的所有因数按照 "质因子 \(p_i\) 有没有出现" 分为 \(2^{质因子个数}\) 类。设状态 \(f[S]\) 表示,从 \(S\) 这个状态开始填的方案数,答案取 \(f(0)\)。\(S\) 记录所有的 \(2^{质因子个数}\) 类的数被冲突了 0, 1, >1 次的情况
考虑枚举一个还能放的类别 i ,然后枚举和这个类别冲突的类,它们会被多冲突一次,更新状态
相当于我们希望多填一个 i 类别中的数,但是具体能放多少种数呢?这就需要在对 n 质因分解的时候乘法原理一下
由于最多有 6 个质因子,每个情况用 4 进制存,恰好需要 \(2\cdot 2^6 = 128\) 位空间,用 __uint128_t
即可
s2oj623. D.多重集合问题
ZJOI 经典整体二分板子。整体二分过程中线段树一下,注意别锅了就行。