CF1562 Codeforces Round 741

Codeforces Round #741 (Div. 2)

C - Rings

题意

给出一个二进制串 SS,长度为 NN,你可以在上面做 [l,r][l, r] 的截断,函数 f(l,r)f(l,r) 表示:将 SS[l,r][l,r] 的截断取出,然后转换为十进制的数。

要求找出两对不同的 (l1,r1),(l2,r2)(l_1, r_1), (l_2, r_2) 满足以下条件:

  • 1l1r1n,r1l1+1n21\leqslant l_1\leqslant r_1\leqslant n, r_1-l_1+1\geqslant\lfloor\frac{n}{2}\rfloor

  • 1l2r2n,r2l2+1n21\leqslant l_2\leqslant r_2\leqslant n, r_2-l_2+1\geqslant\lfloor\frac{n}{2}\rfloor

  • l1l2l_1\neq l_2r1r2r_1\neq r_2 至少有一个满足。

  • 存在一个非负整数 kk,使得 f(l1,r1)=f(l2,r2)kf(l_1, r_1) = f(l_2, r_2) \cdot k

题目保证有解,任意给出一组解即可。

数据范围:2N2×1042\leqslant N \leqslant 2\times 10^4

思路

不要把 kk 想的很复杂,可以就考虑几个简单的,如 0,1,20, 1, 2 即可。

这个题就是构造出一种解就完事了,所以进行分类讨论。

  • 如果 SS 中所有字符都相等,则直接输出 [1,n1],[2,n][1, n-1], [2, n] 即可,因为他们直接相等。

由于题目要求取出的串长度大于等于 n2\lfloor \frac{n}{2}\rfloor,所以考虑从 SS 串的 n2\left\lfloor\frac{n}{2}\right\rfloor 位置作为截断,分左右进行讨论。

  • 如果 SS 的左半部分位置 xn2x\leqslant \left\lfloor\frac{n}{2}\right\rfloor 处为 00,则输出 [x,n],[x+1,n][x, n], [x+1, n],因为前导零去掉后,他们直接相等。

  • 如果 SS 的右半部分位置 x>n2x > \left\lfloor\frac{n}{2}\right\rfloor 处为 00,则输出 [1,x],[1,x1][1, x], [1, x-1],因为后置零,可以通过 ×2\times 2 得到,f(1,x)=f(1,x1)2f(1,x)=f(1,x-1)\cdot 2

以上就已经讨论完了所有可能情况了,按情况输出即可。

时间复杂度 O(T×N)O(T\times N)

D - Two Hundred Twenty One

题意

给出一个长度为 NN 的字符串 SSQQ 次询问,每次询问一个区间 [li,ri][l_i, r_i]

对于数列 a1,a2,,ana_1, a_2, \ldots, a_n,定义“不同符号和”(sign-variable):

s({an})=a1a2+a3a4++(1)n1an=i=1n(1)i1ais(\{a_n\}) = a_1-a_2+a_3-a_4+\cdots + (-1)^{n-1}\cdot a_n= \sum_{i=1}^n(-1)^{i-1}\cdot a_i

现在数列 a1,a2,,ana_1, a_2, \ldots, a_n 只有 +1+11-1 构成,通过只含有正负号的字符串 SS 给出
如果 ai=1Si=+a_i=1\Rightarrow S_i=\texttt{+}ai=1Si=-a_i=-1\Rightarrow S_i=\texttt{-}

每次询问给出区间 [li,ri][l_i, r_i],设字符串 T=SliSli+1SriT = S_{l_i}S_{l_i+1}\cdots S_{r_i},求至少要从 TT 中删除多少个字符才能使得 s(T)=0s(T) = 0,并给出每次删除的字符位置。(第一个问题是D1所要求的,第二个问题是D2所要求的)。

数据范围:1N,Q3×1051\leqslant N, Q\leqslant 3\times 10^5

思路

我们先不考虑 SS 的子串问题,先考虑整个 SS 串。

s(l,r)=i=lr(1)i1ais(l, r) = \sum_{i=l}^r(-1)^{i-1}a_i,表示 s(S)s(S)[l,r][l, r] 这一段的不同符号和。

f(i)f(i) 为去掉 SS 串中第 ii 个字符后变为 SS',整个 SS' 的不同符号和,即 f(i)=s(S)f(i)=s(S')

命题1:f(i)f(i+1)=02|f(i)-f(i+1)| = 0 \text{或} 2

证明:

不难发现:

f(i)=s(1,i1)s(i+1,n)f(i+1)=s(1,i)s(i+2,n)f(i)f(i+1)=s(i,i)+s(i+1,i+1)=aiai+1\begin{aligned} &f(i)= s(1, i-1) - s(i+1, n)\\ &f(i+1)=s(1,i)-s(i+2, n)\\ \Rightarrow & |f(i)-f(i+1)|=|s(i, i)+s(i+1, i+1)|=|a_i-a_{i+1}| \end{aligned}

则:

  • ai=ai+1a_i=a_{i+1} 时,f(i)f(i+1)=0|f(i)-f(i+1)|=0

  • aiai+1a_i\neq a_{i+1} 时,f(i)f(i+1)=2|f(i)-f(i+1)| = 2

QED

下面这个结论不难证明:

命题2:S|S|s(S)s(S) 同奇偶性,也就是字符串长度和字符串的不同符号和的奇偶性相同。

因为 +1+11-1 之和会发生抵消,抵消以后字符总数 2-2 不影响奇偶性,所以最终的不同符号和奇偶性与开始时的字符总长奇偶性相同。

所以,如果 s(S)=0s(S) = 0 则一定有 S|S| 为偶数。

命题3:当 s(1,n)0s(1,n)\neq 0 时,f(1)f(n)0f(1)\cdot f(n) \leqslant 0

证明:

命题等价于证明 f(1)f(1)f(n)f(n) 异号,或者至少有一个为 00

f(1)=s(2,n)=a1s(1,n)f(n)=s(1,n1)=s(1,n)an\begin{aligned} &f(1)=-s(2, n)=a_1-s(1,n)\\ &f(n)=s(1, n-1)=s(1, n)-a_n\\ \end{aligned}

由于 s(1,n)1|s(1, n)| \geqslant 1,所以 f(1)f(1)f(n)f(n) 的符号只能取决于 s(1,n)s(1,n) 的符号,a1,ana_1, a_n 对它们的影响太小,而 s(1,n)s(1, n)f(1),f(n)f(1),f(n) 中的符号正好是一正一负,所以 f(1),f(n)f(1),f(n) 只能异号,或者至少一个为 00

QED

下面给出删除方法

n=Sn=|S| 为奇数,则 f(i)f(i) 为偶数,因为它从 SS 中删除了一个字符。

又通过命题1知,相邻的 f(i),f(i+1)f(i), f(i+1) 之间差值为 0022,由命题3知,f(1),f(n)f(1), f(n) 异号,则一定存在 kk,使得 f(k)=0f(k)=0,可以通过反证法证明。(类似于连续函数的零点存在定理)

则说明,对于长度为奇数的串,我们一定可以找到 f(k)=0f(k)=0,即将 aka_kSS 删除即可满足题意。

如果长度为偶数的串,可以先删除 ana_n 使得它的长度变为奇数且 s(1,n1)s(1, n-1) 不会发生变化,然后再按照奇数的删除方法删除。

综上,最大的删除字符个数不会超过2个。

拓展到任意 SS 的子串 TT 方法很简单,只需要求出 s(T)s(T) 即可,所以可以通过维护函数 ss 的前缀和完成。

于是对于长度为 nn 的字符串 SS

  • s(S)=0s(S) = 0 输出 00

  • nn 为奇数,输出 11

  • nn 为偶数,输出 22

时间复杂度 O(N)O(N)

下面给出 D1(easy version) 的代码:

对于 D2 (hard version) 只需要求出每次奇数长度时删除的位置 kk 即可。

我们知道计算函数零点,可以通过二分完成,所以直接二分零点即可。

时间复杂度 O(NlogN)O(N\log N)

E - Rescue Niwen!

题意

给出一个长度为 NN 的字符串 SS,以 SS 的子串:S1,S1,2,S1,3,,S1,n,S2,S2,3,S2,4,,S2,n,,Sn1,Sn1,n,SnS_1, S_{1, 2}, S_{1, 3}, \ldots, S_{1, n}, S_2, S_{2, 3}, S_{2, 4}, \ldots, S_{2, n}, \ldots, S_{n-1}, S_{n-1, n}, S_n,构成的字符串序列中,最长单调递增子序列长度为多少?(字符串排序方法按照字典序排序,单调在这里是指严格单调

数据范围:1N50001\leqslant N \leqslant 5000

思路

最开始想先预处理出来所有子串的字典序大小,用字典序大小代替原来的字符串序列,然后直接通过 lower_bound 求最长上升子序列,这样复杂度是 O(N2logN2)O(N^2\log N^2) 理论上过不了,最终优化到了 3s,实在写不进 2s 了,最后放弃了这种写法,后来看题解发现这道题有很好的性质。

如果字符串 Sl1,r1S_{l_1, r_1} 在最长上升子序列中,则 Sl1,nS_{l_1, n} 也一定在其中。

所以如果 Sl2,r2S_{l_2, r_2} 考虑从前一个转移,就只用考虑从 Sl1,nS_{l_1, n} 进行转移,保证 Sl2,r2>Sl1,nS_{l_2, r_2} > S_{l_1, n}

这里可以通过求每个后缀 Sl1,n,Sl2,nS_{l_1, n}, S_{l_2, n} 的 lcp(最长公共前缀)完成,设它们的lcp长度为 kk

f(i)f(i) 表示左端点从 1i1\sim i 的最长上升子序列长度,用贪心的思路进行转移。

f(i)=max(ni+1,f(j)+ni+1k),j<if(i) = \max(n-i+1, f(j) + n-i+1-k), j < i,且保证 Si+k>Sj+kS_{i+k} > S_{j+k}

至于两个后缀的lcp可以直接暴力dp得到,这里复杂度也只是 O(N2)O(N^2)

时间复杂度 O(N2)O(N^2)

正确代码:

尝试后的错误代码,使用SAM求字典序,然后lower_bound求解最长上升子序列:


CF1562 Codeforces Round 741
https://wty-yy.github.io/posts/3451/
作者
wty
发布于
2021年8月28日
许可协议