学懂字符串

38 篇文章 0 订阅
13 篇文章 0 订阅

1.双色球

题目

有两个字符串 S , T S,T S,T 均只由 R , B R,B R,B 两种字符组成。开奖时,有一组非空字符串 ( P , Q ) (P,Q) (P,Q) 均由 0 , 1 0,1 0,1 组成,并将 S , T S,T S,T 中的 R , B R,B R,B 字符分别替换为 P , Q P,Q P,Q 字符串。也就是说, S , T S,T S,T 会变成一大堆 P , Q P,Q P,Q 等的重复拼接。如果进行替换后有 S = T S=T S=T,那就中奖了。

将不同的 P , Q P,Q P,Q 满足 max ⁡ ( ∣ P ∣ , ∣ Q ∣ ) ⩽ n \max(|P|,|Q|)\leqslant n max(P,Q)n 并且能够使 S , T S,T S,T 中奖的数量记为 f ( S , T ) f(S,T) f(S,T) 。现在给出由 RB? 三种字符构成的 S ′ , T ′ S',T' S,T(长度不超过 3 × 1 0 5 3\times 10^5 3×105)与 n    ( n ⩽ 3 × 1 0 5 ) n\;(n\leqslant 3\times 10^5) n(n3×105),问,将每个 ? 随机替换为 RB 之一后,得到的 f ( S , T ) f(S,T) f(S,T) 的期望。输出对大质数取模。

思路

如果没有问号怎么做?反正我是连这个都不会。真不愧是简单例题

考虑 P , Q P,Q P,Q 有什么性质。首先,如果 S , T S,T S,T 同时以 RB 开头或结尾,这对 P , Q P,Q P,Q 没有任何约束作用,可以删去。删去之后,如果 S , T S,T S,T 都是空串,那我没话说了,直接输出 ( 2 n + 1 − 1 ) 2 (2^{n+1}-1)^2 (2n+11)2 走人。如果其中之一是空串,那么 puts("0") 完事儿。接下来考虑 S , T S,T S,T 都非空。

不妨设 ∣ P ∣ ⩽ ∣ Q ∣ |P|\leqslant|Q| PQ 。由于 S , T S,T S,T 的开头字符不同,则替换后的开头字符串是 P , Q P,Q P,Q,若想匹配,必须使 P P P Q Q Q 的前缀。类似地, P P P 还需要是 Q Q Q 的后缀。所以我们得到了性质一。

  • P P P 需要是 Q Q Q 的一个 b o r d e r \rm border border

这是我们利用开头、结尾得到的。试着利用一下第二个位置吧。

不妨设
S = Q ⋯ T = P P P ⋯ P ⏟ k 个 P Q ⋯ \begin{aligned} S&=Q\cdots\\ T&=\underbrace{PPP\cdots P}_{k 个 P}Q\cdots \end{aligned} ST=Q=kP PPPPQ

如果 k ⋅ ∣ P ∣ ⩾ ∣ Q ∣ k\cdot |P|\geqslant |Q| kPQ,那么 P P P Q Q Q 的周期。如果 k ⋅ ∣ P ∣ < ∣ Q ∣ k\cdot|P|<|Q| kP<Q 呢?注意 T = k × P + Q T=k\times P+Q T=k×P+Q,末尾上是一个 Q Q Q 。它要和 Q Q Q 匹配,需要 Q Q Q 存在长度为 ∣ Q ∣ − k ⋅ ∣ P ∣ |Q|-k\cdot|P| QkP b o r d e r \rm border border,也就是 k ⋅ ∣ P ∣ k\cdot|P| kP 的周期。如果 P P P 重复 k k k 次是一个周期,肯定也会有 P P P Q Q Q 的周期。于是我们找到了性质二。

  • P P P 需要是 Q Q Q 的一个周期。

P P P Q Q Q b o r d e r \rm border border 说明 ∣ Q ∣ − ∣ P ∣ |Q|{\rm-}|P| QP Q Q Q 的周期。根据 弱周期引理1 可知 gcd ⁡ ( ∣ P ∣ , ∣ Q ∣ − ∣ P ∣ ) = gcd ⁡ ( ∣ P ∣ , ∣ Q ∣ ) \gcd(|P|,|Q|{\rm-}|P|)=\gcd(|P|,|Q|) gcd(P,QP)=gcd(P,Q) Q Q Q 的周期。而 P P P 又是 Q Q Q 的前缀,所以它也是 P P P 的周期。更巧妙的是,它是 整周期(周期长度是字符串长度的因数)。

那么我们得到了这样一个结论:存在字符串 L L L 使得 P = p × L ,    Q = q × L P=p\times L,\;Q=q\times L P=p×L,Q=q×L 。为了不重复计数,应当规定 gcd ⁡ ( p , q ) = 1 \gcd(p,q)=1 gcd(p,q)=1 p ⊥ q p\perp q pq

既然如此,可见 L L L 的长相并不重要,只要 S , T S,T S,T L L L 的个数一样即可。不妨设 S R S_R SR S S S R R R 的数量, S B , T R , T B S_B,T_R,T_B SB,TR,TB 同理,则
a n s = ∑ L = 1 n ∑ p = 1 ⌊ n L ⌋ ∑ q = 1 ⌊ n L ⌋ [ p ⊥ q ] [ p S R + q S B = p T R + q T B ] × 2 L ans=\sum_{L=1}^{n}\sum_{p=1}^{\lfloor{n\over L}\rfloor}\sum_{q=1}^{\lfloor{n\over L}\rfloor}\big[p\perp q\big]\big[pS_R+qS_B=pT_R+qT_B\big] \times 2^L ans=L=1np=1Lnq=1Ln[pq][pSR+qSB=pTR+qTB]×2L

右边的真值括号,可以稍微化简一下。记 Δ R = S R − T R ,    Δ B = T B − S B \Delta R=S_R-T_R,\;\Delta B=T_B-S_B ΔR=SRTR,ΔB=TBSB ,方程可以写成
p ⋅ Δ R = q ⋅ Δ B p\cdot \Delta R=q\cdot \Delta B pΔR=qΔB

特殊讨论一下 Δ R = Δ B = 0 \Delta R=\Delta B=0 ΔR=ΔB=0 的情况,因为 0 0 0 的很多倍数关系很特殊 😂 此种情形下 p , q p,q p,q 只需要互质。所以
a n s = ∑ L = 1 n 2 L ( 2 ∑ j = 1 ⌊ n L ⌋ φ ( j ) − 1 ) ans=\sum_{L=1}^{n}2^L\left(2\sum_{j=1}^{\lfloor{n\over L}\rfloor}\varphi(j)-1\right) ans=L=1n2L2j=1Lnφ(j)1

括号里面的求和,是先求和、再乘二、最后减一,经典的计算互质数对。这个可以 O ( n ) \mathcal O(\sqrt{n}) O(n ) 整除分块一下。

除去上面的情况,不妨设 Δ R ≠ 0 \Delta R\ne 0 ΔR=0 。那么 p ⊥ q p\perp q pq p ⋅ Δ R p\cdot\Delta R pΔR q q q 的倍数 ⇒ Δ R \Rightarrow \Delta R ΔR q q q 的倍数。

k = Δ R q = Δ B p ∈ Z k=\frac{\Delta R}{q}={\Delta B\over p}\in\Z k=qΔR=pΔBZ Δ R = k q ,    Δ B = k p ⇒ k = gcd ⁡ ( Δ R , Δ B ) ⇒ \Delta R=kq,\;\Delta B=kp\Rightarrow k=\gcd(\Delta R,\Delta B)\Rightarrow ΔR=kq,ΔB=kpk=gcd(ΔR,ΔB)
p = Δ B gcd ⁡ ( Δ R , Δ B ) ,    q = Δ R gcd ⁡ ( Δ R , Δ B ) p={\Delta B\over\gcd(\Delta R,\Delta B)},\;q={\Delta R\over\gcd(\Delta R,\Delta B)} p=gcd(ΔR,ΔB)ΔB,q=gcd(ΔR,ΔB)ΔR

发现 p , q p,q p,q 的解与 L L L 无关。所以,最终实际等价于
a n s = ∑ L = 1 ⌊ n max ⁡ ( p , q ) ⌋ 2 L ans=\sum_{L=1}^{\lfloor{n\over\max(p,q)}\rfloor}2^L ans=L=1max(p,q)n2L

这个可以 O ( 1 ) \mathcal O(1) O(1) 算,只要预处理 2 x    ( 1 ⩽ x ⩽ n ) 2^x\;(1\leqslant x\leqslant n) 2x(1xn) 即可。所以,没有问号的情况解决啦

有问号呢?发现答案只跟 Δ R , Δ B \Delta R,\Delta B ΔR,ΔB 有关。考虑枚举增量。令 Δ R , Δ B \Delta R,\Delta B ΔR,ΔB 为不考虑问号时的差值,设 S ? , T ? S_?,T_? S?,T? 代表问号的数量,用 F ( r , b ) F(r,b) F(r,b) 表示上面的过程,则
a n s = ∑ d = − T ? S ? F ( Δ R + d , Δ B − S ? + T ? + d ) ∑ i = 0 + ∞ ( S ? i ) ( T ? i − d ) ans=\sum_{d=-T_?}^{S_?}F(\Delta R+d,\Delta B-S_?+T_?+d)\sum_{i=0}^{+\infty}{S_?\choose i}{T_?\choose i-d} ans=d=T?S?F(ΔR+d,ΔBS?+T?+d)i=0+(iS?)(idT?)

这个式子没准儿写错了。大家懂我的意思就行。打代码的时候可以自己推一推。

后面那个组合数 = ∑ i = 0 S ? ( S ? S ? − i ) ( T ? i − d ) = ( S ? + T ? S ? − d ) =\sum_{i=0}^{S_?}{S_?\choose S_?-i}{T_?\choose i-d}={S_?+T_?\choose S_?-d} =i=0S?(S?iS?)(idT?)=(S?dS?+T?) 可以 O ( n ) \mathcal O(n) O(n) 预处理出所有 ( S ? + T ? x ) {S_?+T_?\choose x} (xS?+T?) 然后 O ( 1 ) \mathcal O(1) O(1) 查。

显然 F ( 0 , 0 ) F(0,0) F(0,0) 最多发生一次。总复杂度
O ( n + n ) = O ( n ) \mathcal O(n+\sqrt{n})=\mathcal O(n) O(n+n )=O(n)

2.听天由命

题目

对于 01 01 01 S S S,定义 ζ i \zeta_{i} ζi 为第 i i i 个字符开始的后缀。再定义
F ( i , j ) = max ⁡ { k    ∣    lcp ⁡ ( ζ i , ζ j − k + 1 ) ⩾ k } F(i,j)=\max\big\{k\;\big\vert\;\operatorname{lcp}(\zeta_i,\zeta_{j-k+1})\geqslant k\big\} F(i,j)=max{klcp(ζi,ζjk+1)k}

即,使得 lcp ⁡ ( ζ i , ζ j − k + 1 ) ⩾ k \operatorname{lcp}(\zeta_i,\zeta_{j-k+1})\geqslant k lcp(ζi,ζjk+1)k 的最大 k k k 值。现在你要求出 ∑ i = 1 ∣ S ∣ − 1 ∑ j = i + 1 ∣ S ∣ F ( i , j ) \sum_{i=1}^{|S|-1}\sum_{j=i+1}^{|S|}F(i,j) i=1S1j=i+1SF(i,j) 。为了不取模,让 ∣ S ∣ ⩽ 1 0 6 |S|\leqslant 10^6 S106 吧。

为了与题目名「听天由命」吻合,保证 S S S 使用线性同余随机生成。

思路

问题真的就要靠「听天由命」解决。首先将 F F F 转化为 b o r d e r \rm border border 。而 b o r d e r \rm border border 要出现至少两次。

S S S 的一个长度为 L L L 的子串。假如它在另一个地方也出现过,那么每一位都要与它匹配。所以概率是 2 − L 2^{-L} 2L 。任选两个长度为 L L L 的子串都累加一次概率,这是一个很大的上界(很多情况重复计算了),但是也只有不到 n 2 2 L n^2\over 2^L 2Ln2 ,只要你取 L = 2 log ⁡ n + 20 L=2\log n+20 L=2logn+20 ,概率就低至 0.000001 0.000001 0.000001如果这都    W A    \sout{\;\tt WA\;} WA了那我确实没办法了)。

所以,我们相信 L ⩽ O ( log ⁡ n ) L\leqslant \mathcal O(\log n) LO(logn) 。有了这个,我们可以考虑枚举一个 b o r d e r \rm border border(一共只有 O ( n L ) \mathcal O(nL) O(nL) 个嘛),然后直接 ( c n t 2 ) × {cnt\choose 2}\times (2cnt)× 长度就完事儿了……吗?

b o r d e r \rm border border 需要是最长。直接枚举一个 b o r d e r \rm border border 不一定是最长的。不过这也很容易避免,就是 ( c n t 2 ) × ( {cnt\choose 2}\times( (2cnt)×(长度 − - b o r d e r \rm border border 长度 ) ) ) 呗。因为这个枚举的 b o r d e r \rm border border 对应的串,也被它的 b o r d e r \rm border border 计算了恰好一次。

怎么求 b o r d e r \rm border border 呢?对 ( n − L + 1 ) (n-L+1) (nL+1) 个长度为 L L L 的子串都做一遍 k m p \rm kmp kmp 就行。

复杂度 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) ,且代码实现不难。然而没写过代码的我有什么资格说呢

3. C t r l + C \rm Ctrl+C Ctrl+C

题目

O n e I n D a r k \sf OneInDark OneInDark 有一篇博客要写。这篇博客可以抽象为字符串 S S S 。现在,他想要发布这篇博客,不过打字实在是太累了,他想要利用 C t r l + C \rm Ctrl+C Ctrl+C 合理省事。

具体而言, O n e I n D a r k \sf OneInDark OneInDark 认为,一口气打出一段文字(即一个字符串)会产生 b b b 的劳累值(与字符串长度无关)。注意必须是一口气打完,不能中断。但是 C t r l + C \rm Ctrl+C Ctrl+C 需要用鼠标选中文本,所以代价是 a × ( a\times( a×(文本长度 ) ) ) 的劳累值。注意:即使一个字符串没有被粘贴,愚蠢的 O n e I n D a r k \sf OneInDark OneInDark 还是要复制它一次。粘贴呢? C t r l + V \rm Ctrl+V Ctrl+V 是多么爽的过程,不会带来劳累!

比如文章 I    a m    a b a b a b a \rm I\;am\;abababa Iamabababa ,可以进行如下操作:打出 I    a m    a \rm I\;am\;a Iama 并复制,产生 b + 6 a b+6a b+6a 的劳累值(空格也是字符);打出 b a \rm ba ba 并复制,产生 b + 2 a b+2a b+2a 的劳累值;然后粘贴两次,不产生劳累值。

现在的唯一问题是,最小劳累值是多少?如果这个值太大, O n e I n D a r k \sf OneInDark OneInDark 只好说 “我有一个绝妙的想法,可是这个 c s d n \sout{csdn} csdn太丑 网速太慢写不了。”

有多篇文章,但是总长不超过 5 × 1 0 5 5\times 10^5 5×105 且单篇文章长度不超过 1 0 5 10^5 105

思路

我会用 S [ i : j ] S[i:j] S[i:j] 表示字符串 S S S 的第 i i i 个字符到第 j j j 个字符形成的子串。确实有点丑,习惯就好。

问题转化一下:将原字符串分段,如果第 i i i 段的最小循环节长度为 r r r 则代价为 a r + b ar+b ar+b ,求最小代价。

d p \tt dp dp 的想法很自然,只是不容易优化。有两个难点,一是转移边太多,二是判断最小循环节长度很难。

事实证明,不是第二个问题难,只是我见得太少。老师给了个串串划分的题目(或许是给错了 😐),我不是很懂内在联系。不管怎么说,这一点是对的:如果 r r r 要连续出现 k k k 次,那么至少要连续出现 2 2 2 次,而 连续出现 2 2 2(我们称为 “平方串”)是可以求解的。这个东西与优秀的拆分是很相似的。

考虑一个长度为 2 L 2L 2L 的 “平方串” 。如果把原序列的 x L ( x ∈ N + ) xL(x\in\N^+) xL(xN+) 位置打一个标记,“平方串” 一定恰好碰到两个相邻的标记。利用这个性质,我们考虑从标记反推 “平方串” 。

L ( x ) L(x) L(x) 表示第 x x x 个标记和第 x − 1 x-1 x1 个标记能够往左匹配多少。 R ( x ) R(x) R(x) 则是往右。形如

L(x)   bacd#....bacd#......
R(x)   ....#snmcb...#snmcb.

这俩拼在一起,不就是一个 “平方串” 吗?很简单吧?并且标记总数是 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) 的,求 L ( x ) , R ( x ) L(x),R(x) L(x),R(x) 可以用后缀数组查询 l c p lcp lcp,总复杂度 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn)但是确实想不到啊

好,我们学会 “平方串” 的判断了。然后 d p \tt dp dp 还是跑不动。没关系,跑不动就建图,图常常有更优美的性质。假设有一个 “平方串” 是 S [ i : i + 2 L − 1 ] S[i:i+2L-1] S[i:i+2L1],那么 d p i + 2 L − 1 dp_{i+2L-1} dpi+2L1 可以从 d p i − 1 dp_{i-1} dpi1 转移而来。可是相差 3 L 3L 3L 呢?显然不能暴力连边了。 3 L 3L 3L 等价于两个 “平方串” 同时满足,必然可以缩成一种路径。

每个点建一个虚点 i L ′ i'_L iL 表示 已经上车了,步长为 L L L 。上车的代价是 a r + b ar+b ar+b 而下车不花钱,像极了现实中的公交车。往下坐一个站,需要此处仍是 “平方串” 。形式化的:

如果有一个以 i − L i-L iL 开头的长度为 2 L 2L 2L 的 “平方串”,那么 i ← ( i + L ) L ′ i\leftarrow (i+L)'_L i(i+L)L 权值为 a L + b aL+b aL+b,再连 i L ′ ← ( i + L ) L ′ i'_L\leftarrow (i+L)'_L iL(i+L)L 权值为 0 0 0,也要连 i L ′ ← ( i − L ) L ′ i'_L\leftarrow (i-L)'_L iL(iL)L 权值为 0 0 0

这样显然是正确的。 ( i + L ) → i L ′ (i+L)\rightarrow i'_L (i+L)iL 表示直到 i − L i-L iL 都是以 L L L 作为循环节。走 ( i + L ) L ′ → i L ′ (i+L)'_L\rightarrow i'_L (i+L)LiL 表示直到 i − L i-L iL 都是以 L L L 作为循环节。走 i L ′ → ( i − L ) i'_L\rightarrow(i-L) iL(iL) 则完成转移。

此时,边数肯定是 3 × ( 3\times( 3×(平方串个数 ) ) ) 的。点数则为 2 × ( 2\times( 2×(平方串个数 ) + n )+n )+n 。能否进一步优化呢?

有些 “平方串” 是没用的,因为它们有一个更小的周期,选用这个更小的周期作为 r r r 就更优。定义 “本原平方串” 为,满足 ∣ S ∣ |S| S 除以最小循环节长度 = 2 =2 =2 的字符串 S S S

【留坑待填】根据 R u n s    T h e o r e m \rm Runs\;Theorem RunsTheorem ,只有 O ( n ) \mathcal O(n) O(n) 个本质不同的 “本原平方串”,可以在 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) 复杂度内找到。英文论文有点长,没读完。

4.金拱门

题目

金拱门公司需要一个新的标志。它们想整一个那样的:某个字符串写很多次,整体结构形成一个 M M M

然而这个提议很快被玩坏了。因为那个字符串要用 M M M 拼凑而成, M M M 则又是多个字符串形成的……

具体而言,一个字符串 S S S 的迭代次数为,其所有在 S S S 中出现过至少 2 2 2 次(毕竟 M M M 需要两个拱门嘛)的子串 S ′ S' S 的迭代次数中最大的一个 + 1 +1 +1 。如果没有 S ′ S' S 存在,迭代次数为 1 1 1(玩不起了)。形式化的,
f ( S ) = max ⁡ S ′    a p p e a r    a t    l e a s t    t w i c e f ( S ′ ) + 1 f(S)=\max_{S'\;{\rm appear\;at\;least\;twice}}f(S')+1 f(S)=Sappearatleasttwicemaxf(S)+1

对于给定串 S ( ∣ S ∣ ≤ 2 × 1 0 5 ) S(|S|\le 2\times 10^5) S(S2×105) 请求出其迭代次数,即 f ( S ) f(S) f(S) 的值。保证 S S S 由小写字母组成。

思路

对于 f ( S ) f(S) f(S) 来说,要么 S ′ S' S 是其后缀,要么不是。对于 S ′ S' S 不是后缀的情况,可以直接由 f ( S ) f(S) f(S) 去掉末尾字符得到。所以只考虑 S ′ S' S 是其后缀的情况。

S S S 有很多个后缀,长度越短越容易出现过两次。而长度越长 S S S 越大,即 ∀ S ′ ⫅ S ,    f ( S ′ ) ≤ f ( S ) \forall S'\subseteqq S,\;f(S')\le f(S) SS,f(S)f(S),所以我们需要找出最长的一个。

能否在 S S S S A M \tt SAM SAM p a r e n t    t r e e \rm parent\;tree parenttree 上二分呢?还是用权值线段树合并维护 e n d p o s endpos endpos 的话,复杂度是 O ( n log ⁡ 2 n ) \mathcal O(n\log^2n) O(nlog2n) 的。

这里就有一个常见套路了:如果 附加权值是 1 1 1,那么附加权值不会影响决策点。也就是说,如果 f ( S 1 ′ ) < f ( S 2 ′ ) f(S'_1)<f(S'_2) f(S1)<f(S2) 了,哪怕 S 1 ′ S'_1 S1 + 1 +1 +1 也只能跟 S 2 ′ S'_2 S2 打个平手。而 f ( S ) = f ( S ′ ) + [ S ′    a p p e a r    a t    l e a s t    t w i c e ] f(S)=f(S')+[S'\;{\rm appear\;at\;least\;twice}] f(S)=f(S)+[Sappearatleasttwice] 恰好满足这一条件。

所以我们直接用最大的 f ( S ) f(S) f(S),也就是 p a r e n t    t r e e \rm parent\;tree parenttree 上的父亲……吗?如果 f f f 相等,就要取最短者了。利用并查集,快速查找相等的 f ( S ) f(S) f(S) 中最短的 S S S 。那么 f ( S ) f(S) f(S) 直接用 f a ( S ) fa(S) fa(S) 在并查集中的根节点转移就行了。

复杂度 O ( n log ⁡ n + ∣ Σ ∣ ⋅ n ) \mathcal O(n\log n+|\Sigma|\cdot n) O(nlogn+Σn) 即可完成。


  1. 弱周期引理:若字符串 S S S 存在两个周期 x , y x,y x,y 满足 x + y ≤ ∣ S ∣ x+y\le|S| x+yS gcd ⁡ ( x , y ) \gcd(x,y) gcd(x,y) 也是 S S S 的周期。简要证明: S i = { S i + x S_i=\{S_{i+x} Si={Si+x S i − y } = S i + x − y ⇒ ∣ x − y ∣ S_{i-y}\}=S_{i+x-y}\Rightarrow|x-y| Siy}=Si+xyxy 为周期 ⇒ gcd ⁡ ( x , y ) \Rightarrow \gcd(x,y) gcd(x,y) 为周期(过程类似更相减损)。 ↩︎

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值