两个关于子段和的题

前几天和同事聊天,聊到前几天的北京数学高考题。最后一个题还挺有意思的,我和同事 yy 了好久都不会:

给定两个序列 {ai},{bi}∈[n]n\{a_i\}, \{b_i\} \in [n]^n,证明存在四个正整数 la≤ra,lb≤rbl_a \leq r_a, l_b \leq r_b 使得

∑i=laraai=∑i=lbrbbi.\sum_{i=l_a}^{r_a} a_i = \sum_{i = l_b}^{r_b} b_i.

在想这个题的时候,我想到了曾经做 POI 的时候见过的一个题:

给定一个大小为 nn 的序列 aa,其中 ai∈{1,2}a_i \in \{1, 2\}。

现在有 mm 个询问,每次给定一个 kk,要你找出一个和为 kk 的子段,或者输出不存在。

数据范围为 n≤107,k≤105n \leq 10^7, k \leq 10^5。

高考题

定义 At=∑i=1taiA_t = \sum\limits_{i=1}^t a_i 为 aa 的前缀和,BtB_t 为 bb 的前缀和。原题有一个提示:不妨令 An≤BnA_n \leq B_n,定义 ri=min⁡{0≤j≤n:Ai≤Bj}r_i = \min \{0 \leq j \leq n: A_i \leq B_j\}。考虑 di=Bri−Aid_i = B_{r_i} - A_i,注意到当 ri>0r_i > 0 时有

B∗ri−1<Ai≤B∗ri,B*{r_i - 1} < A_i \leq B*{r_i},

故有 di<Bri−Bri−1≤nd_i < B_{r_i} - B_{r_i - 1} \leq n,而 ri=0r_i = 0 意味着 Ai=0A_i = 0,所以 i=0i = 0,而我们又有 d0=0d_0 = 0,综上有:

∀0≤i≤n,0≤di<n.\forall 0 \leq i \leq n, \quad 0 \leq d_i < n.

由于我们有 n+1n + 1 个 did_i,但是不同的 did_i 只有 nn 个,所以必定存在 di=djd_i = d_j,这也就意味着

B∗ri−Ai=B∗rj−Aj,B*{r_i} - A_i = B*{r_j} - A_j,

证毕。

POI

我看到这个题的第一反应是 FFT,但是 FFT 有三个缺点:

  • 难写;
  • 慢,这里 nn 的范围是 10710^7,FFT 估计太慢了;
  • 最重要的一点,FFT 没法输出位置……

后来实在不会只好去看 tutorial,发现就一句话的事:

如果存在一个和为 kk 的子段且 k>2k > 2,那么必定存在一个和为 k−2k - 2 的子段。

证明很简单,假设 [i,j][i, j] 的子段和为 kk,我们考虑 aia_i 和 aja_j:

  • 如果 ai=2a_i = 2,那么 [i+1,j][i + 1, j] 满足要求;
  • 如果 aj=2a_j = 2,那么 [i,j−1][i, j - 1] 满足要求;
  • 否则必定有 ai=aj=1a_i = a_j = 1,那么 [i+1,j−1][i + 1, j - 1] 满足要求。

于是,我们只要找到最大的和为奇数的子段和最大的和为偶数的子段即可。全序列肯定是其中一个,另一个就看第一个 1 和最后一个 1 出现的位置就可以了。