Loading

模拟赛8.7 解题报告

T1 转圈圈

题意:由 \(n-1\)\(0\) 和一个 \(1\) 组成序列 \(a_{1...n}\),已知 \(1\) 的初始位置为 \(s\)。你每次可以选择一段长为 \(k\) 的区间,然后翻转这个区间。有 \(m\) 个位置全程都不能出现 \(1\),问对于每个 \(i(1\le i\le n)\),使得位置 \(i\) 上的数变为 \(1\) 的最小翻转次数,若无法做到输出 \(-1\)\(1\le s\le n,\space 1\le n,k,m\le 10^5\)

若数字 \(1\) 当前处于位置 \(i\),不难发现,当 \(k\) 为奇数时 \(1\) 只能变到与 \(i\) 奇偶性相同的位置,否则只能变到与 \(i\) 奇偶性相异的位置,这启示我们从奇偶性的方面考虑。显然,\(1\) 可以变到 \(i-(k-1),i-(k-3),...,i+(k-3),i+(k-1)\) 这些位置。

还有一个条件,若 \(1\)\(i\) 变到 \(j\),钦定 \(j>i\),条件为:

\[\min(i-1,n-j)\ge \frac{(k-1-(j-i))}2 \]

即我们选的 \(j\) 不能太靠边缘。比如 \(k=7,i=1,j=3\),显然翻转不了。

知道了所有条件,我们考虑如何设计算法。很容易想到一个 \(O(nk)\)\(\text{BFS}\),但会超时。一种方法是按奇偶性把位置分类,然后线段树优化建图;另一种方法是观察发现每个 \(dis_u\) 都只会被更新一次,更新过后我们就直接跳过 \(u\),因此可以拿两个并查集,一个往左合并,一个往右合并,快速找到第一个没有更新过的点。

T2 扌舌 口丂 匚儿 酉己

题意:给出一个由 \(\text{(,),?}\) 组成的字符串,每个 \(\text{?}\) 是通配符(可以换成 \(\text{(,)}\) 二者之一),问有多少个子串满足存在一种通配符赋值方案使得该子串括号序列合法。\(1\le n\le 10^6\)

考虑如何判断一个带通配符的括号序列是否合法。维护两个值 \(s,k\)\(s\) 表示把 \(\text{'('}\) 看做 \(1\)\(\text{')'}\) 看做 \(-1\) 时此时扫到的前缀的值的和,\(k\) 表示目前有多少个 \(\text{'?'}\) 赋值成了 \(\text{')'}\)

设当前字符为 \(c\),若当前字符非通配符,那么直接令 \(s\leftarrow s+\text{val}(c)\);否则把通配符看做右括号 \(\text{')'}\),令 \(s\leftarrow s-1,k\leftarrow k+1\)

若当前 \(s<0\),考虑调整通配符的取值,把一个赋值为 \(\text{')'}\) 的通配符改成 \(\text{'('}\),那么 \(s\leftarrow s+2,k\leftarrow k-1\)

若当前 \(k<0\),那么当前扫过的前缀必然不合法。

由于本蒟蒻过菜,不能灵活运用思维,想不到二维数点,于是用了一种不用脑子的方法。

回到原问题,考虑右端点 \(r\),对于每个左端点 \(l\),设 \(s_l,k_l\)\(l...r\) 子串维护的两个变量。

当从 \(r-1\rightarrow r\) 时,对于每个 \(l\),一般情况下 \((s_l,k_l)\) 加上的数都是一样的(比如左括号就都是 \(s\) 加一,通配符都是 \(s\) 减一,\(k\) 加一)。我们维护两个值 \(delta,difk\),表示我们统一令 \(s_l,k_l\) 加上的值。当然,我们还需要考虑 \(s_l<0\) 的情况。不妨对 \(s_l\) 作为下标建立若干个二叉堆,存储对应 \(k_l\)。比如 \(s_l=3,k_l=2\) 就在编号为 \(3\) 的堆里存储一个键值为 \(2\) 的点。每次统一加/减后对于编号为 \(-1\) 的堆,我们需要对每个点的键值都减一,然后把这个堆合并到编号为 \(1\) 的点。于是一个左偏树就做完了。

T3 崩原之战([USACO22DEC] Palindromes P

搬过来的题。

考虑如何对单独一个子串 \([l,r]\) 算贡献。设 \(\text{H}\) 出现的位置分别为 \(p_1,p_2,...,p_m\),若 \(m\) 为偶数:

\[\sum_{i=1}^{\frac m2}|(p_i-l)-(r-p_{m-i+1})|=\sum_{i=1}^{\frac m2}|(p_i+p_{m-i+1})-(l+r)| \]

\(m\) 为奇数,若 \(r-l+1\) 为偶数则无解,否则:

\[|\frac{l+r}2 -p_{\frac{1+m}2}|+\sum_{i=1}^{\frac m2}|(p_i+p_{m-i+1})-(l+r)| \]

\(p\) 数列一直不变去对不同的区间做贡献,我们很容易单次 \(O(\log n)\) 解决。

尝试让 \(p\) 数列的变动影响最小化,可以从中间向两边枚举。设原字符串中 \(\text{H}\) 出现在位置 \(P_1,P_2,...,P_M\),分 \(m\) 为奇数/偶数讨论。

  • \(m\) 为奇数,枚举中间的字符 \(\text{H}\) 的位置 \(P-i\),枚举中间点向两边拓展 \(j\) 个字符 \(\text{H}\)(即子串两端 \(\text{H}\) 的位置为 \(P_{i-j}\)\(P_{i+j}\))。

枚举 \(l\in[P_{i-j-1}+1,P_{i-j}],r\in [P_{i+j},P_{i+j+1}-1]\),逐一考虑贡献。

已知当前 \(m=i+2j\),设 \(g_k=p_k+p_{m-k+1}(k\le j)\) ,我们把 \(g\) 从小到大排序,那么若 \(g_s\le l+r,\space g_{s+1}>l+r,\space sum_s=\sum\limits_{x=1}^s g_x\),贡献为

\[(s(l+r)-sum_s)+((sum_m-sum_s)-(m-s)(l+r)) \]

但是 \(O(n^2\log n)\) 不够优秀。发现每次 \(l+r\) 的变动很小,我们可以类似于莫队,用一个桶辅助更新。

T4 抽卡Ⅰ

题意:有 \(n\)\(l\) 位互异二进制数 \(a_{1...n}\),一开始机器会从 \(a_{1...n}\) 中选出一个数,你每次询问机器,机器会有 \(p_i\) 的概率告诉你第 \(i\) 位的值,有 \((1-p_i)\) 的概率不告诉你第 \(i\) 位的值。对于每个 \(i(1\le i\le n)\),若一开始机器选择 \(a_i\),求出你期望询问多少次才能确定机器选的是哪个数。多测,共 \(T\) 组数据。\(1\le T\le10,\space 1\le l\le15,\space 1\le n\le 2^l,\space 0\le a_i\le 2^l\)

枚举每个数暴力 \(\text{DP}\) 显然 T,对于每个数 \(a_i\),不妨考虑如果知道了位置集合 \(S\) 上的值,是否可以确定机器选择的是 \(a_i\)

但是我们仍然很难排除从状态 \(0\rightarrow S\) 的过程中存在可以确定但非 \(S\) 的状态,很难计数。考虑期望的线性性,分开计算,设在询问的过程中,状态 \(S\) 停留的期望次数为 \(t_S\),经过状态 \(S\) 的概率为 \(P_S\),能确定 \(a_i\) 的状态集合为 \(T\),显然答案为

\[\sum_{S\not\in} P_St_S \]

容斥一下,

\[\sum_{S\not\in} P_St_S=\sum_S P_St_S-\sum_{S\in T}P_St_S \]

先思考如何计算 \(P_S,t_S\)。设处于状态 \(S\) 时,继续停留在状态 \(S\) 的概率为 \(g_S\),那么

\[t_S=g_St_S+1 \]

\[t_S=\frac1{1-g_S} \]

然后是 \(P_S\),不难发现,从 \(S\) 转移到 \(T\) 的贡献为

\[\prod_{i\not\in S,i\in T}p_i\prod_{i\not\in S,i\not\in T}p_i\times \frac 1{1-g_S} \]

Q1:两个连乘符为什么不考虑 \(i\in S\) 的情况?

A:因为对于 \(i\in S\) 机器是否给出第 \(i\) 位对此时的 \(S\) 没有用,无需考虑是否给出,概率默认为 \(1\)

Q2:为什么 \(\frac 1{1-g_S}\) 对转移也有贡献?

A:\(S\) 有可能转移到自己(概率为 \(g_S\)),那样子的话转移就没有用,需要去掉这样的情况,乘上 \(\frac 1{1-g_S}\)\(1-g_S\) 为不转移到自己的概率)

此时我们得出了 \(\sum_S P_St_S\) 的值,还需考虑如何计算 \(\sum_{S\in T}P_St_S\)

枚举每个状态必然超时,考虑利用每个状态对答案做贡献。

注意,这里的“状态”是一个三进制数,每一位表示 \(\{\text{0,1,?}\}\),不妨用 \(A\) 来表示这样的状态。

\(f_A\) 表示是否可以用 \(A\) 状态唯一确定一个数 \(\in a_{1...n}\)

若没有满足 \(A\) 状态的数,\(f_A=0\);若有唯一一个满足 \(A\) 状态的数,\(f_A=\text{id}\),即那个数的下标;若有至少两个满足 \(A\) 状态的数,\(f_A=-1\)

事实上我们只需要求满足 \(A\) 状态的数的个数即可得到 \(f_A\)。设 \(pos_A\) 表示 \(A\) 的最低位的 \(\text{?}\) 位置,那么 \(A\) 状态的数分为第 \(pos_A\) 位为 \(0/1\) 两部分,容易求得 \(f_A\)

\(pos_A\) 也容易求:若 \(A\) 的第 \(0\) 位为 \(\text{?}\),那么 \(pos_A=0\);否则 \(pos_A\)\(A\) 去掉最后一位后的的状态的 \(pos\) 加一。

总时间复杂度 \(O(T3^l)\)

posted @ 2023-08-07 21:01  Lgx_Q  阅读(16)  评论(0编辑  收藏  举报