2026.9 杂题

QOJ 14727 Dolls 2

模拟赛 T4,这道题比较困难的地方是找突破口。

观察到对于任意相邻的 \(3\) 个非单调的位置,设为 \(a_{i-1},a_i,a_{i+1}\)。则一定可以将它们划分在两个不同的区间内。如果 \(a_{i-1}\) 是这三个数的中位数,那么可以划分成 \(\{i-1\}\) 和 \(\{i,i+1\}\) 两个。\(a_{i+1}\) 同理。

所以问题就转为选出若干个单调的连续段,使得相邻两端之间值域有交。

这个可以直接 \(O(n)\) dp,注意到拐点是特殊的(将 \(1,n\) 也钦定为拐点),而且任意的合法的一段 \([l,r]\) 都满足要么 \(l\) 是拐点,要么 \(l-1\) 是拐点;同理,要么 \(r\) 是拐点,要么 \(r+1\) 是拐点。所以可以设状态 \(dp_{i,0/1,0/1}\) 表示当前考虑到 \(1\sim i\) 且 \(i\) 是拐点,设 \(j\) 是 \(i\) 前一个拐点,最后一个区间的左端点是 \(j+0/1\),右端点是 \(i-0/1\) 的最大段数。转移是好做的,但是有一种特殊情况是当两个拐带相邻时,设为 \(i-1\) 和 \(i\),可以把 \([i-1,i]\) 中间不视为一个递增的段,将其划分成 \([x,i-1]\) 和 \([i,y]\),再判断两个区间是否有交。

时间复杂度 \(O(n)\)。

提交记录

TopCoder 10780 BouncingDiceGame

模拟赛 T2,独立做出来的。

注意到当 \(x,y\ge n-d\) 时,接下来不管进行任意次操作,任意一方胜利的概率都是 \(\frac 1d\)。

所以设 \(dp_{x,y}\) 为棋子在 \(x,y\) 且先手必胜的概率。

那么当 \(x,y\ge n-d\) 时,有 \(dp_{x,y}=\frac{1}d+\frac{(d-1)^2}{d^2}dp_{x,y}=\frac{d}{2d-1}\)。

其他情况可以直接枚举转移,发现 \(dp_{i,j}\) 需要用到的 \(dp_{x,y}\) 是一个矩形,且 \(\forall x+y>i+j\)。所以按 \(x+y\) 从大到小计算 \(dp_{x,y}\),用二维前缀和优化即可。时间复杂度 \(O(n^2)\)。

提交记录

TopCoder 10737 BuildingRoads

好题啊。

自己做起的,模拟赛 T3。

首先考虑如果只存在一对城市该怎么做。因为一种岩石保证四联通,所以可以考虑最短路,从 \(u\) 走到 \(v\),如果 \(u,v\) 的岩石种类不同,则代价为 \(v\) 的代价;否则为 \(0\)。这样做能对的原因是,如果一种岩石被计算了两次,那么为何不直接沿着这个岩石构成的连通块走呢?所以错解不优,就可以直接最短路。

考虑多对城市怎么办。发现可以多个东西连成一个连通块,类似于一棵树,就是每次选两个节点,合并成一个节点。设 \(dp_{S,x,y}\) 表示将 \(S\) 的节点连城一棵树,且树根在 \((x,y)\) 的最小代价。

转移就是枚举 \(T\),则有:

\[dp_{S|T,x,y}\gets dp_{S,x_1,y_1}+dp_{T,x_2,y_2}+dis(x_1,y_1,x,y)+dis(x_2,y_2,x,y) \]

其中 \(dis(x,y,X,Y)\) 表示从 \((x,y)\) 走到 \((X,Y)\) 的最小代价,且不考虑 \(val(x,y)\) 的贡献。

这样做是 \(O(3^8n^2m^2)\)。过不去。

注意到同种岩石的位置本质相同,还有城市作为特殊点,这样本质不同的点有 \(70\) 个。所以做 Dij 只用做 \(70\) 次,时间复杂度是 \(O(70nm\log {nm})\)。然后 dp 是 \(O(3^870^2)\)。

然后最后答案就是把若干个 \(\{S_1,S_2,S_3,...,S_k\}\) 使得任意一个都包含若干对城市且两两无交,且并为所有城市对。然后答案就是 \(\sum_{i=1}^k\min_{x,y}dp_{S_i,x,y}\)。时间复杂度为 \(O(3^8)\)。

这道题非常好,结合了多种技巧,包括最短路和错解不优思想等。

提交记录

TopCoder 13144 CandidatesSelection

模拟赛 T2,\(n,m\le 10^3\) 的版本。赛时写了个 \(O(n^2m)\),1s 创过去了。

我们发现初始时 \(p_i=i\),所以可以将初始的数组视为一种额外的字符串,满足 \(c_i=i\)。

考虑时间倒流,我们发现当一个相邻的位置第一次被某一个字符串满足 \(c_{p_i}<c_{p_{i+1}}\) 后,后面无论怎么操作都不影响它。而再此之前,只能出现 \(c_{p_i}=c_{p_{i+1}}\)。

所以问题就被转化了,考虑一个字符串 \(c\),设集合 \(S\) 为位置 \(i\) 满足 \(c_{p_i}>c_{p_{i+1}}\),位置集合 \(T\) 满足 \(c_{p_i}<c_{p_i+1}\)。那么问题被转化为,初始时有一个集合 \(X=\varnothing\),每一次你可以选择一个字符串 \(i\) 满足 \(S_i\subseteq X\),然后执行 \(X\gets X\cup T_i\)。问你能否最终让 \(X=U\),就是全集。

这个可以每一次暴力枚举没有加入的字符串判断是否能加入,这样做是 \(O(n^2m)\),用 bitset 可以做到 \(O(\frac{n^2m}w)\)。

其实根本不用。记录 \(cnt_i\) 为字符串 \(i\) 满足 \(c_{p_j}>c_{p_{j+1}}\) 且 \(j\notin X\) 的个数。那么每一次新加入一个元素到 \(X\) 的时候,暴力更新每一个字符串的 \(cnt_i\),若 \(cnt_i=0\) 则可以加入。所以这个就有点像一个拓扑排序。

这样做时间复杂度是 \(O(nm)\)。

提交记录

QOJ 850 Edit Distance Yet Again

模拟赛 T3,去掉了多测,范围开到了 \(k\le 3\times 10^3,n\le 10^6\)。时限 3s。

这个编辑距离,直接做是 \(O(nm)\) 的。然后发现 \(k\) 更小,所以 dp 中 \(|i-j|\le k\),类似 AT_abc386_f 的做法,可以做到 \(O(nk)\)。

注意到我们此时的 dp 状态是 \(dp_{i,p}=w\) 表示已经处理了第一个字符串的 \(1\sim i\),且处理第二个字符串的 \(1\sim j\) 满足 \(j=i+p\) 的最小编辑距离 \(w\)。注意 \(w\le k\),所以考虑继续交换一维。

设 \(dp_{w,p}=i\) 表示最大的 \(i\) 满足 \(j=i+p\),考虑第一个字符串的 \(1\sim i\) 和第二个字符串的 \(1\sim j\),最小的编辑距离为 \(w\)。因为 \(i,j\) 的差是固定的,所以 \(i\) 越大越好。

转移就是考虑 \(dp_{w,p}=i\),算出 \(j=i+p\)。然后枚举下一个到底是添,删,还是改。

\[dp_{w+1,p}\gets i+1+lcp(i+2,j+2) \\dp_{w+1,p-1}\gets i+1+lcp(i+2,j+1) \\dp_{w+1,p+1}\gets i+lcp(i+1,j+2)\]

这个 \(lcp(i,j)\) 表示第一个字符串从第 \(i\) 个字符开始的后缀和第二个字符串从 \(j\) 开始的后缀的最长公共前缀。转移瓶颈在于求 \(lcp\),这个用 SA 解决即可。

时间复杂度为 \(O(n\log n+k^2)\)。

提交记录

QOJ12214 Dates

有点类似模拟费用流。

二分图匹配是一个拟阵,所以可以直接将所有女孩按收益值从大到小考虑,能加入就加入。

那么怎么判断一个女孩加入后是否存在分配方案呢?发现这个问题本质上是一个 Hall 定理判定问题,我们将女孩排序后,对于区间任意一个女孩集合 \(S\),我们设其覆盖的位置的 \(a\) 之和为 \(N(S)\),则需要满足 \(|S|\le |N(S)|\)。

但是我们发现,只取所有连续的女孩区间作为 Hall 的判定也是充分的。因为满足 \(l_i\le l_{i+1},r_i\le r_{i+1}\)。所以当选的女孩集合的 \([l_i,r_i]\) 可以被分成多段使得任意两段值域不交时,若每个段都合法则可以证明这个集合也合法。若所有 \([l_i,r_i]\) 连成了一段,此时设选的最小的女孩编号为 \(i\),最大的为 \(j\),那么不妨把编号为 \([i,j]\) 的女孩全取了,此时 \(|S|\) 变大,\(|N(S)|\) 不变。所以是充分的。

所以就变成了这样一个式子:

\[\forall i\le j, \sum_{k=i}^jc_k\le \sum_{k=l_i}^{r_j}a_k \]

其中 \(c_k=[编号为\ k\ 的女孩是否被取]\)。

那么移一下项,则有

\[(\sum_{k=1}^jc_k-\sum_{k=1}^{r_j}a_k)+(\sum_{k=1}^{l_i-1}a_k-\sum_{k=1}^{i-1}c_k)\le 0 \]

定义

\[X_i=\sum_{k=1}^ic_k-\sum_{k=1}^{r_i}a_k\\Y_i=\sum_{k=1}^{l_i-1}a_k-\sum_{k=1}^{i-1}c_k \]

则条件变为:

\[\max_{i\le j}(Y_i+X_j)\le 0 \]

这个式子就很能用线段树求出,因为 \(i\le j\)。

那么我们在考虑一个女孩 \(i\) 是否加入时,先将其加入进去,对于 \(X[i,n]\) 都加一,\(Y[i+1,n]\) 都减一,然后判断最大值是否 \(\le 0\)。如果满足要求则保留,否则则改回来。

时间复杂度 \(O(n\log n)\)。

提交记录

CF1209G2 Into Blocks (hard version)

模拟赛 T4

首先注意到我们可以找出分割线,对于位于 \(i\) 和 \(i+1\) 之间的分割线存在当且仅当不存在颜色在 \([1,i]\) 和 \([i+1,n]\) 中同时都出现过。

那么可以发现,我们一定会将两个分割线之间的所有颜色操作成一种颜色。首先不可能分得更短,因为每个段都不可能再被分割。其次没必要将多个段合并成一段,这样没必要,还会浪费次数。

对于两个分割线之间,其代价是段的长度减去区间众数的出现次数(即出现次数最多的颜色的出现次数)。于是可以做到单次 \(O(n)\) 解决。

形式化一点,我们记录 \(c_i\) 为同时出现在区间 \([1,i]\) 和 \([i+1,n]\) 的颜色数量。注意到修改操作等价于对 \(c\) 进行区间加减。那么分割点就满足 \(c_i=0\)。所以我们需要支持区间加减,以及相邻的两个 \(0\) 之间的众数出现次数。

我赛时没想到如何用线段树维护这个。

注意到 \(c_i\ge 0\),而 \(c_i=0\) 一定是全局最小值。所以可以将一个区间里的最小值视为分割点,求出相邻两个最小值之间的代价。那么当最小值为 \(0\) 时答案就是维护的答案,否则整个序列就为一段,答案为 \(n-众数出现次数\)。

那么问题在于,对于两个区间进行合并时,如何维护新形成的中间那一段的代价?我们需要求出其众数出现次数,通常来说这个东西很难用线段树维护,但是这道题有性质:如果这是一个合法的段(最小值为 \(0\)) 则所有颜色要么全部出现在这个区间,要么没在这个区间出现。

所以我们可以对于每个颜色,记录一个数组 \(w\),然后将一种颜色的第一次出现的位置的 \(w\) 赋值为该颜色的出现次数。那么区间众数就可以直接计算为区间内 \(w\) 的最大值。这样修改也是 \(O(1)\) 个位置。这是一个错解不优思想。

时间复杂度 \(O(n+q\log n)\)。实现的时候可以把 \(c_0=c_n=0\),这样最小值直接就是 \(0\),直接输出答案即可,不用特判。

提交记录

QOJ 1877 Matryoshka Dolls

模拟赛 T2,但是时间 4s,空间 1GB。

我赛时的想法是值域分块,然后对于值域在一个块内,找到所有位置在 \([l,r]\) 的数,求出相邻的两个数的位置的绝对值。注意到 \([l,r]\) 本质上只有 \(O(B^2)\) 个,可以用链表提前求出来,这样时空都是 \(O(nB)\) 的。然后查询就是所有块都 \(O(1)\) 查,相邻块权值单独算就可以了,时间复杂度 \(O(q\frac{n}B)\)。块长开 \(B=1600\) 可以过模拟赛的版本。

但是这个题存在 \(\text{polylog}\) 做法。

考虑分治怎么做。对于区间 \([L,R]\),我们希望算出所有满足 \(L\le l\le mid<r\le R\) 的询问 \([l,r]\) 的答案

我们设区间 \([l,mid]\) 的值为 \(p_l,p_{l+1},...,p_{mid}\)。我们设区间 \([l,mid]\) 的答案为 \(S_l\),然后和区间 \([mid+1,r]\) 合并时,对于排序后相邻的两个值 \(p_x<p_y\),若存在 \(z\in[mid+1,r]\) 满足 \(p_x<p_z<p_y\),则会从原本的 \(|x-y|\) 变成 \(|x-z|+|y-z|\)。但是这个 \(z\) 可能有很多个,导致权值的式子很难确定,所以我们考虑,如果存在一个这样的 \(z\),我们就把权值改为 \((mid-x)+(mid-y)\)。对于右半那个区间,我们后面再计算即可。

所以对于每个这样的一对 \(x,y\),我们可以得到一个操作 \((z,w)\) 表示若 \(r\ge z\),则让 \(S_l\) 会加上 \(w\)。特别的,大于 \(p_{l\sim mid}\) 的最大值和小于 \(p_{l\sim mid}\) 最小值,同样可以得出一个操作。我们记录 \(D_z\) 为所有 \((z,w)\) 的 \(w\) 之和。所以左区间的最终权值 \(S_l+\sum_{i=mid+1}^rD_i\)。这个 \(S_l\) 可以预处理。

因为不存在修改,所以预处理时我们考虑在区间 \([L,mid]\) 内 \(l\) 往左挪一位会发生什么,实际上会多添加一个 \(p_{l-1}\),然后考虑排序后与 \(p_{l-1}\) 相邻的两个值,它们本身会有一个操作,但是加入 \(p_{l-1}\) 后原本的操作会消失,然后又加入两个新的操作。所以操作的变化是 \(O(1)\) 的。于是开一个主席树维护下所有 \(l\in[L,mid]\) 的操作即可。空间和时间都是 \(O(n\log^2 n)\)。

以上所有的东西对右半区间 \([mid+1,r]\) 再维护一份同理的东西。

查询区间 \([l,r]\) 就只用做两次主席树上查。

总时间复杂度 \(O(n\log^2n+q\log n)\)。

P17286 「IXOI R2」Horizon Blue

考虑分治,对于区间 \([L,R]\),考虑分治中心 \(mid\),那么设 \(f_i=\max_{j=i}^{mid} a_j,g_i=\max_{mid+1}^ia_j\)。那么查询区间 \([l,r]\) 满足 \(l\le mid<r\),则该询问在这个区间的贡献是 \(\sum_{i=l}^{mid}\sum_{j=mid+1}^r\max(f_i,g_j)\)。

对于每一个 \(i\),设 \(d_i\) 为最大的 \(d_i\) 满足 \(mid+d_i\le R\) 且 \(g_{mid+d_i}<f_i\)。那么询问 \([l,r]\) 在这里 \(i\) 的贡献就是 \(f_i\times \min(r-mid,d_i)\)。然后注意到 \(f_i\) 单调不升,所以 \(d_i\) 单调不升,所以在查询 \([l,r]\) 时,对于 \(i\in [l,mid]\) 计算上面式子的和就可以直接线段树二分。

那么如果不带修的话,查询区间 \([l,r]\) 就只用提前预处理所有被 \([l,r]\) 完全包含的区间的答案,然后对于 \(L\le l\le mid<r\le R\) 的区间,用线段树二分就可以 \(O(\log n)\) 去求。时间复杂度 \(O(n\log n+q\log^2n)\)。

但是带修怎么办,注意到如果右区间某个数增加对于左区间的 \(g\) 的更改是一段区间,所以可以直接区间覆盖。同样的,如果左区间某个数修改对于左区间的 \(f\) 更改也是一段区间。所以直接区间赋值即可。线段树上维护 \(\sum f_i,\sum d_i\sum f_id_i\) 即可。

时间复杂度 \(O(n\log n+q\log^2 n)\)。

提交记录

CF392E Deleting Substrings

这个题能看得出来是区间 dp,但是我们发现,最难处理的就是如何维护留下的数的个数,也就是准备放在下一次删的个数?

这个东西显然不能直接维护,因为这样至少要 \(O(n^4)\) 了。

其实很简单,因为这个序列有一个性质,就是相邻两个数的差为 \(1\)。也就是说,如果我们把一次删去的这个峰形子序列分成两个部分,一个单调递增,一个单调递减。那么我们只需要知道该子序列的最左侧的位置 \(l\),以及最右侧的位置 \(r\),还有峰值的位置 \(k\),那么如果这个子序列合法,那他一定是 \(\{a_l,a_l+1,...,a_k-1,a_k,a_k-1,...a_r+1,a_r\}\)。所以个数就是 \(2a_k-a_l-a_r+1\)。

于是我们把这个单峰子序列拆成两个单调子序列后,只用知道这两个单调子序列的首尾就可以算出它们合起来的个数。设 \(f_{l,r},g_{l,r}\) 表示区间 \([l,r]\) 中剩下一个以 \(l\) 为起点,\(r\) 为终点,且满足单调性和相邻两个数差为 \(1\) 的单增/单减子序列的最大价值。同时设 \(h_{l,r}\) 为将 \([l,r]\) 区间删完的最大价值。

转移是简单的,只需要注意原序列不用全部删完,所以再做一个 dp 算就行了。

提交记录

posted @ 2026-10-26 20:16  Daylighten  阅读(3)  评论(0)    收藏  举报