一言:
虚伪的眼泪,会伤害别人,虚伪的笑容,会伤害自己。
——反叛的鲁鲁修
竟然没有第一时间想到状压,还是太蒟了。。
这题看到一个子集,再加上子集和的范围只需要考虑小于 的情况,其实就应该直接想到状压的,不知道当时我是范什么抽了,竟然没想到。。。
我们定义 表示前 个数中,每个骰子选出的数所能构造出的小于等于 的子集和只能是 状态上二进制为 的数。
显然,我们可以考虑枚举一个 分别表示第 个骰子会投出那个数。和从 的那个状态转移过来。那么下面就是考你位运算的时候。
首先已经至少出现 这个状态了,接着,由于投出了 ,所以当前状态就变成了 。但是由于是子集和,所以以前的子集和可以全部加上 构成新的子集和,也就是 ,但是由于这样可能会超出 ,所以有 ,所以用人话说就是 。
另外,对于 的情况可能会导致左移的太多炸精度,所以直接特殊处理就可以了。
题目里面那个期望其实没什么大用的,就是用来唬人的。
仔细读题之后,就会发现题意实际上就是对于一个点 他的权值是 ,他的父亲是 ,他会对所有他 步以内的祖先的答案全部加上 ,最后输出每个点的答案除以 对一个质数取模。
由于是向上跳 步,我们考虑是否可以倍增。(鬼知道是怎么想到这个倍增的。)我们可以一步一步来理解这个过程:
如果是向上跳 步,且当前每个数组中已经存好了 步的情况。(具体储存什么后面会讲)注意,由于是倍增处理,我们要把 和 数组也处理到倍增以后的情况,也就是 就表示当前跳完 步后,他的 步会跳到哪里,所以跳完 ,都有 。(仔细思考可以发现,这个和树上倍增的思想类似。)对于 ,我们储存已经跳完 步每个点的答案。仔细想可以发现,我们对于 只需要统计从 这些步数跳来的,在加上 ,就可以得到答案。仔细思考一下,这不就是 。
最后统计答案的时候,我们将所有 的二进制位是 的 加到答案上就可以了。(并记得在此时重新初始一下 数组)
还是要配合代码才能方便理解啊。。。。
-
当答案是关于选出的数的一些子集的限制时,且这些限制并不是很多,可以通过二进制表示出来。那么请考虑状态压缩。
-
当你在题目中看到期望的时候,不要紧张,大概率都需要将问题的模型转化一下。
-
如果要求 个东西经过 步的贡献之和,可以考虑把 拆成 这样一个一个的二进制位。然后从 开始,每次让次数加一次,也就是通过一些手段求出经过 这些步数的贡献,然后每次将 这些步数的贡献加在一起,就可以得到 步的贡献之和。相当于将时间复杂度从 优化到 。
-
不只是树可以倍增,仔细想想,基环树或者只有一个父亲的图是不是都可以倍增?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】