0%

题目大意

题面

Alice 手上有两个长度为 NN 的二进制字符串 AABB(仅由字符 01 组成)。

Alice 玩如下游戏。初始时她的分数为 00。每次迭代:

  • 她把两个字符串的首字符乘积加到分数上,即分数增加 A1B1A_1 \cdot B_1

  • 如果 A1=B1A_1 = B_1,就把 AA 替换为 left_shift(A)\mathrm{left\_shift}(A)

  • 否则把 BB 替换为 left_shift(B)\mathrm{left\_shift}(B)

对于二进制字符串 S=S1S2SLS = S_1 S_2 \ldots S_Lleft_shift(S)\mathrm{left\_shift}(S) 定义为删去首字符并追加到末尾:

left_shift(S)=S2S3SLS1\mathrm{left\_shift}(S) = S_2 S_3 \ldots S_L S_1

现在有 QQ 次独立询问。第 ii 次询问给出整数 KiK_i,需要求出恰好执行 KiK_i 次迭代后 Alice 的分数。各次询问彼此独立,每次都视为从初始字符串 AABB 重新开始。

输入格式

  • 第一行一个整数 TT,表示测试用例组数。

  • 每组测试用例共四行:

    • 第一行两个整数 NNQQ,分别表示字符串长度与询问次数。
    • 第二行是二进制字符串 AA
    • 第三行是二进制字符串 BB
    • 第四行 QQ 个空格分隔的整数 K1,K2,,KQK_1, K_2, \ldots, K_Q

输出格式

对每组测试用例输出一行,包含 QQ 个空格分隔的整数,第 ii 个整数是执行 KiK_i 次迭代后 Alice 的分数。

数据范围

  • 1T1041 \leq T \leq 10^4

  • 1N,Q1061 \leq N, Q \leq 10^6

  • 1Ki10121 \leq K_i \leq 10^{12}

  • 所有测试用例的 NN 之和、QQ 之和各自不超过 10610^6

  • 时间限制 33 秒;内存限制 1.51.5 GB

样例

样例 1

输入:

1
2
3
4
5
6
7
8
9
2
2 5
01
10
1 3 5 7 9
3 4
101
100
1 6 7 12

输出:

1
2
0 0 1 1 2
1 2 3 4

样例解释

样例 1 的第一组测试用例,前 55 次迭代的详细过程:

  1. A=01, B=10A = \texttt{01},\ B = \texttt{10}。分数增加 01=00 \cdot 1 = 0。此时 A1B1A_1 \neq B_1,令 Bleft_shift(B)=01B \leftarrow \mathrm{left\_shift}(B) = \texttt{01}

  2. A=01, B=01A = \texttt{01},\ B = \texttt{01}。分数增加 00=00 \cdot 0 = 0。此时 A1=B1A_1 = B_1,令 Aleft_shift(A)=10A \leftarrow \mathrm{left\_shift}(A) = \texttt{10}

  3. A=10, B=01A = \texttt{10},\ B = \texttt{01}。分数增加 10=01 \cdot 0 = 0。此时 A1B1A_1 \neq B_1,令 Bleft_shift(B)=10B \leftarrow \mathrm{left\_shift}(B) = \texttt{10}

  4. A=10, B=10A = \texttt{10},\ B = \texttt{10}。分数增加 11=11 \cdot 1 = 1。此时 A1=B1A_1 = B_1,令 Aleft_shift(A)=01A \leftarrow \mathrm{left\_shift}(A) = \texttt{01}

  5. A=01, B=10A = \texttt{01},\ B = \texttt{10}。分数增加 01=00 \cdot 1 = 0。此时 A1B1A_1 \neq B_1,令 Bleft_shift(B)=01B \leftarrow \mathrm{left\_shift}(B) = \texttt{01}

1,3,5,7,91, 3, 5, 7, 9 次迭代后的累计分数依次为 0,0,1,1,20, 0, 1, 1, 2

思路讲解

一句话

KK 最大到 101210^{12},逐步模拟必炸;这题的结构是「run-length 周期 + 首块 + 整圈 + 零头」三段式,外面再套个二分。

状态机:matched / mismatched

得分 A1B1A_1 \cdot B_1 只有在 A1=B1=1A_1 = B_1 = 1 时是 1,其他都是 0。而且「谁前进」完全绑定在 A1=?B1A_1 \stackrel{?}{=} B_1 上,所以过程天然分两态:

  • matchedA1=B1A_1 = B_1):左移 AA,得分 =A1= A_1

  • mismatchedA1B1A_1 \ne B_1):左移 BB,得分 =0= 0

matched 段持续到 AA 跨过一个 AA-run(A1A_1 翻转),mismatched 段持续到 BB 跨过一个 BB-run(B1B_1 翻转),两态在 run 边界交替。

🎬 Note: 动画:两态循环切换(对应下方 BasicLoop.mp4)——沿时间轴展示 matched ↔ mismatched 的交替节拍,以及每步谁在动、谁在得分。

Video

状态机结构图(题解 PDF p.2):matched / mismatched 两态 + 切换条件 + 状态表

Phase:一个 matched + 一个 mismatched

把相邻的 matched + mismatched 合成一个 phase。每个 phase 吃掉 AA 的 1 个 run + BB 的 1 个 run,步数 =len(A-run)+len(B-run)= \mathrm{len}(A\text{-run}) + \mathrm{len}(B\text{-run})

关键不变量:

每过一个 phase,A1,B1A_1, B_1 各翻 1 次,相对关系还原——所以所有 phase 的内部子结构都和第 1 个一样,只需判一次 cA=?cBc_A \stackrel{?}{=} c_BcA,cBc_A, c_B 就是 A1,B1A_1, B_1 的初始值)。后面零头分类直接吃这条不变量。

跳过首块 + 周期性

AA 从首块内部起步,所以首块是残缺的(长度 L0AL_0^A,与 A1A_1 同字符的极长前缀)。跳过首块后从 L0AmodNL_0^A \bmod N 开始把 AA 当循环串扫一圈,得到完整 run 长度序列 r0A,r1A,,rkA1Ar^A_0, r^A_1, \ldots, r^A_{k_A-1},段长总和 =N= N,之后按段数 kAk_A 为周期重复。BB 侧同构。

注意 段数 kAk_A 和段数 kBk_B 一般不相等,两套预处理彼此独立——同一个 PP(已过 phase 数)在 AA 侧和 BB 侧走的圈数、零头段号可以完全不一样。

🎬 Note: 动画:首块拎出 + 整圈跳跃(对应下方 SkipJump.mp4)——可视化「首块 L0AL_0^A 单独算一份 + 后面按段数周期扫圈」的分解。

Video

A = 00011011 示例(PDF p.3):首块 L_0^A = 3 单独拎出;跳过首块后循环 run 序列 r^A = (2,1,2,3),段数 k_A = 4,末段与首块物理同一个 run(同蓝色)

B = 11110000 示例(PDF p.4):L_0^B = 4,r^B = (4,4),段数 k_B = 2。注意本例 k_A = 4 ≠ k_B = 2,两侧预处理独立

三段式 O(1)O(1) 函数

走完 PP 个 phase == phase 1 吃首块 ++ 剩下 P1P - 1 个 phase 按周期跑完。两侧各自拆 P1=qk+rP - 1 = q \cdot k + r

fA(P)  =  L0A+qAN+pref_a[rA]f_A(P) \;=\; L_0^A + q_A \cdot N + \mathrm{pref\_a}[r_A]

fB(P)  =  L0B+qBN+pref_b[rB]f_B(P) \;=\; L_0^B + q_B \cdot N + \mathrm{pref\_b}[r_B]

gA(P)  =  L0AcA+qAWA+pref_score_A[rA]g_A(P) \;=\; L_0^A \cdot c_A + q_A \cdot W_A + \mathrm{pref\_score\_A}[r_A]

三段式 O(1) 函数汇总(PDF p.6):f_A / f_B / g_A 同构,只差「走段长还是得分」「用 A 侧还是 B 侧周期」

🎬 Note: 动画:预处理数组构造(对应下方 Preprocess.mp4)——动态展示两侧 run 长度序列、pref_a / pref_b 前缀和、整圈得分 W_A 是怎么一步步填出来的,三段式 O(1) 公式里的参数全部在这步落地。

Video

WA=iriArateiW_A = \sum_i r^A_i \cdot \mathrm{rate}_i 是一整圈的得分(ratei\mathrm{rate}_i 就是第 iiA1A_1 的值:偶 ii1cA1 - c_A、奇 iicAc_A)。P=0P = 0直接 return 0,别套公式——不然首块项会白加,而且 P1=1P - 1 = -1 做下取整和取模在 C++ 里行为还依赖符号约定,徒增隐患。

二分 + 零头(这个二分应该是单纯我们不大能推出来这个最大能走)

fA(P)+fB(P)f_A(P) + f_B(P) 关于 PP 单调递增,直接二分找最大 PP^* 使 fA(P)+fB(P)Kf_A(P^*) + f_B(P^*) \le K。单查询 O(logK)O(\log K)

零头 R=K(fA(P)+fB(P))R = K - (f_A(P^*) + f_B(P^*)) 落在第 P+1P^* + 1 个 phase 里——用那个不变量,查一次 cA=?cBc_A \stackrel{?}{=} c_B 定案:

cAc_A vs cBc_B phase 内部结构 RR 步贡献
cA=cBc_A = c_B 先 matched 后 mismatched min(R, lenA)rateA\min(R,\ \mathrm{len}_A) \cdot \mathrm{rate}_A
cAcBc_A \ne c_B 先 mismatched 后 matched max(RlenB, 0)rateA\max(R - \mathrm{len}_B,\ 0) \cdot \mathrm{rate}_A

口诀:cA=cBc_A = c_BAA 在前,RR 先花在 matched 段;cAcBc_A \ne c_BBB 在前,要先熬过 lenB\mathrm{len}_B 步 mismatched 才落到 matched。代码里 A[0] == B[0] 就是在判这个。

uniform 特判

AABB 全同字符时翻转结构退化(kA=0k_A = 0 之类),奇偶 rate 公式直接出事。把「都 uniform / 只 AA uniform / 只 BB uniform」三类单独闭式处理绕开。通解写完一定要回头扫一遍退化分支,不然很容易暴毙。

复杂度

预处理 O(N)O(N),单次询问 O(logK)O(\log K),总 O(N+QlogK)106+106404×107O(N + Q \log K) \approx 10^6 + 10^6 \cdot 40 \approx 4 \times 10^7,稳过 3 s。

📎 动画与源码

solution.tex.txt

solution.pdf — xelatex 编译产物(12 页 A4)

AC代码

🎬 Note: 动画:代码走读(对应下方 CodeWalkthrough.mp4)——按执行顺序高亮核心函数(预处理、f_A/f_B/g_A、二分主框架、零头分类),配合上面思路节的三段式公式一起看。

Video

心路历程(WA,TLE,MLE……)

题目大意

思路讲解

AC代码

心路历程(WA,TLE,MLE……)

题目大意

给定多组数据。每组有 n 匹马按编号 1..n 排列,m 个饲料槽编号 1..m

初始时第 i 匹马分配到槽 a_i,其中 a_i=0 表示未分配。每个槽的投喂总量 b_i 初始都是 0

需要按顺序执行 q 次操作,每次输入 opt, l, r, x

  • opt=1:把区间 [l,r] 内所有马的分配槽改为 x

  • opt=2:对区间 [l,r] 内每匹马,如果它当前已分配槽(a_i≠0),就给它所在槽增加 x 的投喂量(累加到对应 b_{a_i})。

所有操作结束后,输出 m 个数,表示每个槽最终投喂总量 b_1..b_m

1
2
3
4
5
6
7
8
9
10
11
12
Sample Input
1
6 4 5
1 0 3 2 4 1
2 1 4 3
1 2 5 1
2 1 6 2
1 3 4 4
2 2 5 4

Sample Output
23 3 3 8

样例过程对应含义:

  • 初始分配:[1,0,3,2,4,1],所有 b_i=0

  • 操作 2 1 4 3:马 1..4 中已分配的有 1,3,4 号马,分别给槽 1,3,2 各加 3

  • 操作 1 2 5 1:马 2..5 全部分配到槽 1

  • 操作 2 1 6 2:马 1..6 都已分配,按当前分配给对应槽加 2

  • 操作 1 3 4 4:马 3..4 改分配到槽 4

  • 操作 2 2 5 4:马 2..5 都已分配,按当前分配给对应槽加 4

最终各槽投喂总量为:23 3 3 8

思路讲解

2025 河南省赛——Problem C. Toxel 与宝可梦图鉴(珂朵莉树+值域线段树维护全局信息)(因为这道题目,可以设计珂朵莉树无这个查询操作,只有 assign 操作,因此严格 O(nlogn))(区间等差数列赋值,全局查询最小众数)

PDF

PDF

这个下面的这个避免树状数组清空的技巧还是非常有用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
	void assign(ll la, ll ra, ll val) {
split(la);
split(ra + 1);
auto it = mpODT.lower_bound(la);
#ifdef LOCAL
assert(it->first==la);
#endif
for (; it != mpODT.end();) {
if (it->first > ra) {
break;
}
ll originV = it->second.val;
ll l = it->first, r = it->second.r;
// 这里是做一些事情,比如说累加答案
ll add = tr->query(l, r);
anss[originV] += add;
anss[val] -= add;
it = mpODT.erase(it);
}
mpODT[la] = {ra, val};
}

image

AC代码

AC

https://acm.hdu.edu.cn/contest/view-code?cid=1201&rid=9803

心路历程(WA,TLE,MLE……)

题目大意

题意总结

给定长度为 N 的字符串 S,字符只可能是 01?

把所有 ? 分别替换成 01 后,会得到一个二进制串。

定义“好串”为:所有 1 必须恰好出现在一个连续子串中(可以没有 1,也可以全是 1)。

对一个确定的二进制串,定义 f(S) 为把它变成“好串”的最少操作次数。

一次操作是:选 1 ≤ i < j ≤ N,交换 S[i]S[j]

每个测试用例要求输出两件事:

  • 在所有可能替换方案里,f(S) 的最小可能值

  • 在所有可能替换方案里,f(S) 的最大可能值


输入格式

  • 第一行:整数 T,表示测试用例数。

  • 每个测试用例两行:

    • 第一行:整数 N
    • 第二行:长度为 N 的字符串 S

输出格式

每个测试用例输出一行两个整数:min_f max_f,分别表示最小和最大可能的 f(S)


数据范围

  • 1 ≤ T ≤ 100

  • 2 ≤ N ≤ 2000

  • S[i] ∈ {0,1,?}

  • 所有测试用例的 N 之和不超过 2000


样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Input
6
3
1?1
5
1?0?1
7
1?0101?
9
?????????
8
11010101
6
??011?

Output
0 1
1 1
1 2
0 3
2 2
0 1

样例说明(按测试点)

  • 第 1 组:1?1

    • 最小值:取 111,已经是好串,f=0
    • 最大值:取 101,最少交换 1 次变好串,f=1
    • 所以输出 0 1
  • 第 2 组:1?0?1

    • 无论怎么填,f 的最小和最大都为 1
    • 输出 1 1
  • 第 3 组:1?0101?

    • 可构造到 f=1(如 1101010
    • 也可构造到 f=2(如 1101011
    • 输出 1 2
  • 第 4 组:?????????

    • 最小可到 0(如全 0 或全 1
    • 最大可到 3(如 111000111
    • 输出 0 3
  • 第 5 组:11010101

    • 没有 ?,串固定,f 唯一为 2
    • 输出 2 2
  • 第 6 组:??011?

    • 最小可到 0
    • 最大可到 1
    • 输出 0 1

思路讲解

PDF

所谓的均匀分布,其实就是指二分,因为我们想要尽可能均匀分布,选择的指标是最不均匀的最均匀,这个其实就是一个典型的二分。

AC代码

AC
https://www.codechef.com/viewsolution/1265307182

心路历程(WA,TLE,MLE……)

题目大意

  • 给定长度为 NN 的数组 AA

  • 好数组(good) 的定义:数组中存在至少一个数值 xx,它在该数组中恰好出现一次

    • 例如 [1,2,1][1,1,2] 是好数组(2 只出现一次)。
    • [1,2,1,2] 不是好数组(每个值都出现两次)。
  • 漂亮数组(beautiful) 的定义:这个数组的每一个子数组(连续子段)都是好数组。

    • 例如 [1,2,1] 是漂亮数组;[1,1,2][1,2,1,2] 不是。
  • 你可以进行若干次修改操作:每次选择位置 ii,把 AiA_i 改成任意整数 xx

  • 目标:对每个测试用例,求把原数组变成漂亮数组所需的最少修改次数

  • 输入格式:

    • 第一行是测试组数 TT
    • 每组先给 NN,再给 NN 个整数 A1,,ANA_1,\dots,A_N
  • 输出格式:

    • 每组输出一个整数,表示最少修改次数。
  • 数据范围:

    • 1T1031 \le T \le 10^3
    • 2N5002 \le N \le 500
    • 1AiN1 \le A_i \le N
    • 所有测试用例的 N2N^2 之和不超过 5002500^2

样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
输入
4
3
1 3 1
3
1 1 2
4
1 2 1 2
6
1 1 1 2 1 2

输出
0
1
1
2
  • 样例第 1 组:[1,3,1] 本身已经是漂亮数组,所以答案是 0

  • 样例第 2 组:[1,1,2] 不是漂亮数组,改一次即可(如把第 2 个数改成 3,得到 [1,3,2]),答案是 1

  • 样例第 3 组:[1,2,1,2] 不是漂亮数组,最少改 1 次。

  • 样例第 4 组:[1,1,1,2,1,2] 最少改 2 次。

思路讲解

PDF

AC代码

AC
https://www.codechef.com/viewsolution/1263070965

心路历程(WA,TLE,MLE……)