CSP题解
CSP38 T4 月票发行
题意:长度为 \(n\)(\(10^9\))的字符串有 \(m\)(\(10^6\))个固定为
#,其余能填任意小写字母。问至少有一个 ccf
和一个 cspark 子串,且至少有一个 ccf 出现在
cspark 前的字符串数量。
点击查看题解
ccf 和 ccf 后第一个出现的 cspark
作为特征进行计数,这样就需要求出长度为 \(i\) 没出现 ccf 的数量,长度为
\(i\) 没出现 ccf 与
cspark 的数量。但是想不到好的办法使用 \(O(n)\) 算法可以做到不重不漏。
例如考虑前半段至少出现一次 ccf,后半段至少出现一次
cspark,显然会重复。前面不出现 ccf
然后紧接着放 ccf,之后至少出现一次
cspark(如果规定不出现 ccf
会遗漏,如果规定可出现 ccf
又显然重复)。没有好的计数方法。
直接计数不行,可以考虑正则表达式匹配。.* 简化为
*,题目要求就是可匹配 *ccf*cspark*
的字符串数量。设 dp[i][j] 代表考虑到第 \(i\) 位,最大可以匹配到第
\(j\)
位正则表达式的字符串数量(最大即唯一性,保证字符串计数不重不漏)。转移方法是类似
KMP 的失配转移,具体来说:
*=*+26-c,*c+26-c,*cc+26-c-f;*c=*+c;*cc=*c+c,*cc+c;*ccf= 0(他也可以匹配*ccf*,取最大);*ccf*=*cc+f,*ccf*+26-c,*ccf*c+26-c-s,*ccf*cs+26-c-p,*ccf*csp+26-c-a,*ccf*cspa+26-c-r,*ccf*cspar+26-c-k;*ccf*c=*ccf*+c,*ccf*c+c,*ccf*cs+c,*ccf*csp+c,*ccf*cspa+c,*ccf*cspar+c;*ccf*cs至*ccf*cspar:由*ccf*c至*ccf*cspa转移;*ccf*cspark= 0(他也可以匹配*ccf*cspark*,取最大);*ccf*cspark*=*ccf*cspar+k,*ccf*cspark*+26。
如果当前字符是 #,只有末尾为 *,即
*,*ccf*,*ccf*cspark*
可转移,且由“上一阶段”转移。
然后就过了第一个 subtask ,\(O(11n)\)。
1 |
|
然后考虑这两个转移的 DP
式子只由固定的上一个状态转移而来,可以用矩阵快速幂加快运算。具体而言,#
之间的连续的空格就用第一个矩阵跑矩阵快速幂加速 DP,遇到 #
使用第二个矩阵转移。
然后就过了第二个 subtask,\(O(11^3m\log n)\)。
1 |
|
获得满分需要两个观察。
我们可以发现,不同的区间长度不会多于 \(\sqrt n\),因为长度 \(1+2+3...\) 是等差数列,所以预处理矩阵快速幂的答案可以把这里的时间复杂度降为 \(O(11^3m+11^3\sqrt n\log n)\)。
然后我们发现现在的时间复杂度卡在了 \(m=10^6\) 上,每次遇到 #
都要算两次 \(11^3\)
的矩阵操作。实际上矩阵快速幂题目一般是求向量乘矩阵的某次幂,所以我们直接维护向量,而不是把矩阵都乘起来再乘向量。每次遇到
# 只需要 \(11^2\)
的向量乘矩阵操作,所以变成了\(O(11^2m+11^3\sqrt n\log
n)\),就可以过了。
1 |
|
CSP37 T4 集体锻炼
题意:给定长度为 \(n=10^6\) 的数列 \(a_i\le10^6\),定义 \(f(l,r)=l\times r\times \gcd(a_l,a_{l+1},...,a_r)\)。求 \(\sum_{l=1}^n\sum_{r=l}^n f(l,r)\)。
点击查看题解
注意到如果对于某个左端点 \(L\),前缀 gcd 变化的位置集合为 \(S(L)\),则 \(S(L)\subseteq S(L+1)\cup\{L\}\)。因为随着左端点左移,旧的变化位置有可能会减少,但除了左端点本身不可能增加新的变化位置。所以只需要倒着枚举左端点,维护变化的位置集合,不需要每次都二分查询变化位置。这样可以通过此题。
1 |
|