[ABC249E] RLE Solution

更好的阅读体验戳此进入

题面

给定一种字符串压缩算法:对于连续的相同字母,会压缩成 该字母 + 出现次数 的形式,例如 aaabbcccc 会被压缩成 a3b2c4aaaaaaaaaa 会被压缩成 a10

字符集为英文小写字母,给定 n,p,求对于所有长度为 n 的字符串,有多少满足压缩后的字符串长度严格小于原字符串。对 p 取模。保证 p 为质数。

Solution

DP 比价显然。考虑状态,设 dp(i,j) 表示考虑前 i 个字符,压缩后长度为 j 的方案数。

考虑转移,显然对于某个状态的 i 可以从前面所有长度小于它的 k 转移而来,并且钦定 [k,i] 是相同的,且与 k1 不同。所以转移的时候还需要考虑那一段压缩后的长度,也就是 log10。显然有:

dp(i,j)=k=1idp(k1,jlog10ik+11)×25

这个东西显然是可以前缀和优化的,注意因为第二维的状态,所以要按照 log10ik+1 做,最后的复杂度 O(n3)O(n2logn),且 log 是以 10 为底的,可以通过。

然后这里我们要注意 dp(1,x) 的时候这个东西是可以取到 26 个字符的,而不是 25,所以这里有个小 trick,因为是模意义下的且模数为质数,所以可以直接求个逆元然后令 dp(0,0)=2625modp,这样转移的时候就可以直接按照柿子无脑写了,当然在具体实现的时候,还是推荐直接初始化 dp(i,log10i),这样虽然会使代码略显冗长,但是也会更直观,好调。

这里还有两个易错点,一个是注意枚举状态的时候应为 jn 而非 j<i,因为 ji 的虽然在当前是不合法的,但是转移到后面之后会因被压缩而变得合法,所以也需要记录。

另一个易错点是中间我们会需要求一次 log,这个东西因为数据范围较小,建议直接枚举手写,不过如果非要像我一样用浮点运算,建议直接用库里的 log10,如果一定要用换底做的话记得用 long double,我最开始写的 #define log10(x) (int(log((double)x) / log(10.0)) + 1),然后这个东西因为精度问题会出现 log10(1000)=3,找了好久才发现是这个的问题。

Code

UPD

update-2022_11_30 初稿