我寻思这种“一正常题非要爆改计数嗯堆难度结果整出一托答辩”不应该是模拟赛恰烂钱才能干的事吗,怎么扔 CF 了。真不如来做我们 P11269 爆改版。
考虑 E1 咋做。先考虑快速算出 。如果直接打表你会寄。所以在函数的原本意义上先做一些操作。可以发现,我们只需要保留 中 上为 的那些位,其他位的信息我们可以移动到那些位上。
假如 中有一位为 且 中那一位为 ,那么我们可以将这位扔掉,并将 在 中更低的 位上都赋为 。那么 只在 中有值的位上有值,并且我们并不关心 中有值的位具体是哪些,所以我们可以将其平移到最前面,那么 就变为了 这样的数。更进一步的,我们可以将 最高位之后的位都扔掉,那么新的 最高位和 的最高位相等,于是 一定能被转化成 ,其中 为 最高位,设其为 。
那么我们对 打表,规律就显而易见了:我们有:
那么我们就以 解决了 E1。
考虑解决 E2。由于上述结论, 值显然是 的,那么我们只要算出每堆石子取到每种 值的方案数,那么就能 合并出最终的答案。
观察计算 值的代码:
inline int SG(int a, int x){bool flg = 0;int s = 0;
for (int i = 29;i >= 0;i --){
int aa = a >> i & 1, xx = x >> i & 1;
if (!xx) flg |= aa;
else aa |= flg, s <<= 1, s |= aa;
}
if ((s + 2 & s + 1) == 0) return 0;
if ((s & s - 1) == 0) return __lg(s) ^ 1;
return __lg(s) + 1;
}
我们发现,我们只关注 以及 是否为 形式,并且我们所做的操作就是根据 的取值来往 的后面加一位。
那么我们考虑建出一个识别 串的自动机,只需要识别 以及 两类串,显然这个自动机只有常数个节点。
这样就可以数位 DP 了:从高到低考虑 的每一位,那么我们需要记录;
- 当前考虑到哪一位;
- 是否顶到 的上界;
- 的值;
- 走到了自动机的哪个节点;
- 串中第一个 与串尾的距离。
显然可以枚举这位选 还是 来做到 转移。对于单个数求方案数就是 的。那么总时间复杂度就是 。代码非常好写,E2 喜提 CF 最短解。