DP(优化)

史不分好坏。是史就应该冲进🦖。

细节见其他题解。

P10538

首先建出部分分 sub1 的图,发现是 DAG,于是设点为状态,即即将乘坐 \(j\) 车的最小代价 \(f_j\)。这样的转移就是枚举上一个到这里的车 \(f_i\),加上 \((i,j)\) 时段吃饭的代价 \(w(i,j)\)

显然,这可以使用四边形不等式的优化。于是李超树可以做到 \(O(n\log^2n)\)

P8864

给定一个长度为 \(n\)\(\tt01\) 序列 \(a\)\(q\) 次询问,询问参数 \(k\)

每次询问给定 \(L,R\),其中 \(1\leq L\leq R\leq n\),你可以进行如下操作:

  • 选择一个下标 \(L<i\le R\)
  • \(a_{i-1}\) 赋值为 \(a_{i-1}\oplus a_i\)\(a_{i+1}\) 赋值为 \(a_{i+1}\oplus a_i\)。如果 \(i=n\),则不对 \(a_{i+1}\) 作出改变。其中 \(\oplus\) 表示按位异或运算。

求使得 \([L,R]\) 区间内至多\(k\)\(\tt1\) 的最小操作次数。询问之间相互独立,也就是说,每次询问后重置为初始序列。

先前缀异或和一下。这样就是交换邻项。把数分成 \(k\) 段。进一步地,就是把 \(1\) 分成 \(k/2\) 段。

考察操作的性质:感性的说,当我们开始构建下一段连续 \(1\) 的时候,前面的 \(1\) 一定已经构建好了。这是非常容易理解和证明的。

于是就有 dp:设 \(g(i,j)\) 为把 \([i,j]\)\(1\) 移动到一段的最小交换次数。那么设区间 \([i,j]\) 构建 \(k\) 个连续段的最小代价是 \(f(i,j,k)\),就有

\[f(i,j,k)=\min f(i,p,k-1)+g(p+1,j) \]

先考虑 \(g\) 的计算。对于区间 \([l,r]\),我干的事情一定是把 \(1\) 集中到中心。容易发现一个 \(1\) 的移动次数应当等于它到中心中间的 \(0\) 的个数。所以事实上,我们不需要枚举中心,而是经典中位数结论即可。

然后接下来记 \(f_k(i,j)=f(i,j,k)\),那么 \(f_k,f_{k-1}\) 之间就是 \((\min,+)\) 卷积 \(g\) 的关系。首先可以快速幂做一下。

然后怎么优化?注意到 \(g\) 满足决策单调性,即区间单调性和四边形不等式。区间单调性是显然的,而我们邀请读者把一个更好的四边形不等式证明当作习题(相对航航的而言)。

有引理:

满足四边形不等式的 \(g\) 的任意自幂(在 \((\min,+)\) 卷积下,而 \(\min\) 是更优)都满足四边形不等式。
证明从略。

于是可以 \(O(n^2)\) 完成矩阵乘法,在 \(O(n^2\log n)\) 时间复杂度解决了问题。

Code:https://www.luogu.com.cn/record/159663868

P9746

给定一个长度为 \(n\) 的序列 \(a_1,a_2,\ldots a_n\)

你可以对这个序列进行若干(可能为 \(0\))次操作。在每次操作中,你将会:

  • 选择三个正整数 \(i<j<k\),满足 \(a_i\oplus a_j\oplus a_k=0\)\(k\) 的值不超过此时序列的长度。记 \(s=a_i\oplus a_{i+1}\oplus \cdots\oplus a_k\)
  • 然后,删除 \(a_i\sim a_k\),并在原来这 \(k-i+1\) 个数所在的位置插入 \(s\)。注意,此时序列 \(a\) 的长度将会减少 \((k-i)\)

请你判断是否能够使得序列 \(a\) 仅剩一个数,也就是说,在所有操作结束后 \(a\) 的长度为 \(1\)。若可以,你还需要给出一种操作方案。

\(f(i,j)\) 是能否缩成一个数。这个枚举四个端点(\([i,a],[b,c],[d,j]\))即可。

肯定要想想值域。\(pd(i,j,k)\) 为是否有异或和为 \(k\) 的区间 \(\subseteq [i,j]\)

把前两个区间带上,\(g(i,j)\) 表示 \(i\) 开始,使得两个值为 \(j\) 的(可缩)区间被包含在内的最小右端点。

为了转移这个,设 \(h(i,j)\) 为左端点 \(l>i\) 的区间 \([l,r]\) 满足异或和为 \(j\) 的中 \(r\) 的最小值。那么有 \(g(i,j)=h(k,j)\),其中 \(k\) 是第一个 \(\ge i\) 并且满足 \(pd(i,k,j)\) 的。

这样就可以转移 \(f\)。枚举第三区间的左端点 \(d\) 即可。这样做到了 \(O(n^3)\) 的复杂度。

为了输出方案,记录每个转移的位置即可。

Code:https://www.luogu.com.cn/record/159693658

P9288

经 典 牢 番

Code:https://www.luogu.com.cn/record/159745429

P2305

Code:https://www.luogu.com.cn/record/159814749

CF868E

带权树,有一个晶哥在根,速度为 \(1\),小偷生活在树上,以 \(n\le 50\) 为嚆矢。滥觞于 \(\infty\) 的速度正失去它们的实际意义(🤮)。晶哥遇到小偷的时候小偷就会被抓到,小偷们会尽量使晶哥抓到所有小偷的时间变长,晶哥则相反。求晶哥抓完小偷的时间。

一个晶哥做什么:围堵小偷。这样的围堵需要方向和位置,因此状态需要带 \(u\to v\) 这条有向边;同时,注意到还在 \(u\) 的时候 \(v\) 相对 \(u\) 的子树内的小偷在子树内可以随意移动,而到 \(v\) 的时候还是那些小偷(只不过分好子树了) ,而 \(u\) 相对 \(v\) 子树内的小偷又可以随便动了,于是 dp 状态事实上只需要记录三维信息:\(f(e,x,y)\) 表示 \(e:u\to v\) 这条边走过来,\(u\) 那边有 \(x\) 个小偷,\(v\) 这边有 \(y\) 个小偷所需的时间。

考虑如何转移。定义 \(g(i,j)\) 为目前是 \(v\) 的第 \(i\) 子树(可以滚掉),放了 \(j\) 个小偷在这些子树的时间。现在代入小偷群体(byd 小偷这么团结)来看:枚举这个子树分配 \(k\) 个小偷取 \(\max\)。这个时候再代入晶哥视角:我要尽量优化,对 \(g(i-1,j-k)\)(等后面再出击)和 \(g(e',k,x+y-k)\)\(e'\)\(v\) 进入第 \(i\) 子树的边)取 \(\min\)。最后,让 \(f(e,x,y)=g(m,y)\)\(m\)\(v\) 的子树个数)即可。

Code:https://www.luogu.com.cn/record/159831287

AGC056B

给定整数 \(n\) 以及 \(m\) 对整数。第 \(i\) 对整数为 \((l_i, r_i)\)

请输出可以通过如下方式生成的整数序列 \(x = (x_1, x_2,\cdots,x_m)\) 的个数。答案对 \(998244353\) 取模。

生成方式:

  • 取排列 \(p = (p_1, p_2,\cdots,p_n)\),满足其为一个 \(1\)\(n\) 的排列。
  • 对于任意 \(1\le i \le m\)\(i\),令 \(x_i\)\(p_{l_i}, p_{l_i + 1},\cdots ,p_{r_i}\) 中最大值对应的下标。即 \(p_{x_i} = \max\{p_{l_i}, p_{l_i + 1},\cdots, p_{r_i}\}\)

\(2\le n\le 300,\ 1\le m\le \frac{n(n - 1)}2\)

考虑从序列映射到产生他的多个排列中的一个:从 \(n\)\(1\) 加入数,总是加入到尽量前面。容易发现,这样做一定是合法的(如果能被产生)。

然后考虑这样的排列有什么性质。先区间 dp 搞,设 \([l,r]\) 的最大值位置是 \(k\)\([l,k-1]\) 的最大值位置是 \(k'\),那么一定存在一个限制同时包含 \(k'\)\(k\)。我们邀请读者把充分性当作一个习题。

\(f(l,r,k)\)\([l,r]\)\(\max\) 位置大于等于 \(k\) 的方案数。只需记录 \(g(l,r,k)\) 包含了 \(k\),包含于 \([l,r]\) 中的限制区间的最小左端点即可。

Code:https://www.luogu.com.cn/record/159857850

P5469

小 R 喜欢研究机器人。

最近,小 R 新研制出了两种机器人,分别是 P 型机器人和 Q 型机器人。现在他要测试这两种机器人的移动能力,测试在从左到右排成一排的 \(n\) 个柱子上进行,柱子用\(1 - n\) 依次编号,\(i\) 号柱子的高度为一个正整数 \(h_i\)。机器人只能在相邻柱子间移动,即:若机器人当前在 \(i\) 号柱子上,它只能尝试移动到 \(i - 1\) 号和 \(i + 1\) 号柱子上。

每次测试,小 R 会选取一个起点 \(s\),并将两种机器人均放置在 \(s\) 号柱子上。随后它们会按自己的规则移动。

P 型机器人会一直向左移动,但它无法移动到比起点 \(s\) 更高的柱子上。

Q 型机器人会一直向右移动,但它只能移动到比起点 \(s\) 更低的柱子上。

现在,小 R 可以设置每根柱子的高度,\(i\) 号柱子可选择的高度范围为 \([A_i, B_i]\),即\(A_i \leq h_i \leq B_i\)。小 R 希望无论测试的起点 \(s\) 选在哪里,两种机器人移动过的柱子数量的差的绝对值都小于等于\(2\)。他想知道有多少种柱子高度的设置方案满足要求,小 R 认为两种方案不同当且仅当存在一个 \(k\),使得两种方案中 \(k\) 号柱子的高度不同。请你告诉他满足要求的方案数模 \(10^9 + 7\) 后的结果。

还是最大值分区间。设 \(f(l,r,k)\)\([l,r]\) 中最大值 \(=k\) 的方案数。最大值位置发现就那两种。枚举一下最大值结束。

但是值域太大了。写成 \(f_{l,r}(k)\) 的形式(记得之前自动机那里的柯里化吗?),发现转移类似于 \(f_{l,r}(k)=\left(\sum_{j\le k} f_{l,m}(j)\right)\left(\sum_{j\le k} f_{m+1,r}(j)\right)\),当然要分段。做 \(k\) 的前缀和,就是 \(f_{l,r}(k)=s_{l,m}(k)s_{m+1,r}(k)\)

这是什么?这是函数点乘。根据当 \(l=r\) 时这是一次函数,所以这是分段多项式的卷积。容易证明,每段不超过 \(n+1\) 次。因此保留多项式的(在这个段的)前 \(n+2\) 项值即可。最后前缀和需要前面的最后一项,需要插值一下。

最后时间复杂度是 \(O(n^4)\) 的。

但是实际上能够取到(因为最大值不是任意位置)的区间很少,远小于 \(n^2\),复杂度是可以接受的(看起来不是 \(O(n^2)\) 的?)。

P8290 很类似。

Code:https://www.luogu.com.cn/record/159915725

AGC034E

锐评 T_Q_X 课件。

给你一颗 \(n\) 个节点的树,并用二进制串告诉你哪些节点上有棋子(恰好一颗)。

可以进行若干次操作,每次操作可以将两颗距离至少为 \(2\) 的棋子向中间移动一步。

问能否通过若干次操作使得所有的棋子都在一个点上,如果能,输出最小操作次数,如果不能,输出 \(-1\)

数据范围:\(2 \leq n\leq 2000\)

先枚举一下起点。首先看看操作。具体来说,当原来的子树 dep 和不存在绝对众数时,就可以取到模 \(2\) 的答案。否则就是绝对众数减去其他的数。

\(s(u)\) 是这个子树剩下的棋子的到 \(u\) 距离总和。\(f(u)\) 是其最小值。显然上面的结论可以沿用。结束。

Code:https://www.luogu.com.cn/record/160508146

CF1326G

蛛网树是一颗平面树,满足点是该树的凸包的顶点上等价于其是叶子。

给定一个平面树,求有多少种对点集的划分,使得每个划分出来的集合都是蛛网树。

考虑树形 dp。设 \(f_u\)\(u\) 子树内的划分方案。先考虑两种特殊情况,以 \(u\) 为最浅点的蛛网树只有 \(1,2\) 个点,是容易转移的(因为后面的凸包转移是按边所以这些不会统计到)。

先考虑一个凸包带来的贡献最后应当计算所有凸包带权的和累加到 f 上。设凸包为 \(S\),其带的权应为:

\[\prod_{u\not\in S,fa_u\in S}f_u \]

考虑拆一下贡献。

把到叶子的线延长划分出若干区域。把每个区域内的贡献乘起来就可以了。

中间的那些点一定是在树上的路径(判断时有一些细节,不是半平面交起来!)。直接乘起来即可。这样,就解决了计算权值的问题。

还需要知道:哪些点对有贡献?即哪些点对可能成为相邻的叶子?显然,树上路径点必须在连边的一侧(不妨统一设为左侧),然后根据原树上边转移才能保证没有问题。具体来说,不是按照叶子转移,而是先对子树内的边标号,双向边两个方向不同,然后按照相邻叶子在原树上的起始边转移。

这里的转移类似于 P2924 的转移,先把向量排序,再枚举开始的边和按顺序枚举向量转移,叠加答案即可(注意取消掉只有自己的贡献)。

A 是排序后的向量集合。bh 是边的编号,P 向量的 d 是权值,F,S 是开始边和终止边。x,y 是枚举的起点边。这样的起点边当然必须在某个选定象限内。这样的转移显然是 \(O(n^3)\) 的。

还有一个问题:这个凸包必须存在一个相邻点对,满足他们在树上的路径包含当前处理 f 数组的 \(u\),实际上就是 \(u\) 在凸包叶子的虚树上。这个很容易保证,dp 时搞一下或者容斥一下均可。

P8392

\(2m+1\) 种物品,重量分别为 \(-m,-m+1,\ldots, m-1,m\)。重量为 \(i\) 的物品有 \(a_i\) 个。

你需要拿走若干物品,使得这些物品重量之和恰好为 \(l\)。在此基础上,你需要拿尽可能多的物品。

问在物品重量之和恰好为 \(l\) 的基础上,你最多能拿多少物品。

首先把重量尽量小的东西选上,使得重量在 \((l-m,l]\) 中。

引理:此时方案和最优方案的(选择物品的个数)差之至多为 \(2m\)

我们邀请读者把证明当作一个习题。

然后值域降低了,直接背包即可。

Code:https://www.luogu.com.cn/record/160621156.

CF1292F

给出\(n\leq 60\)个不同的\(\leq 60\)的数,当\(i,j,k\)满足\(a_i,a_j,a_k\)都未被删去,\(a_i | a_j\)并且\(a_i | a_k\)时可以将\(a_k\)删去,求能删除最多数的删除序列数。

首先是强化问题。把这个建成一个闭包 DAG。然后对于弱连通块分别考虑。

然后考虑什么情况可以删尽量多。首先无入度点集合 \(X\) 和剩下一个点肯定删不了。否则,不难证明,任意一个点作为那个 \(a_j\) 作为辅助都可以把剩下的取完。

但这个不足以成立 dp。继续考虑取数过程。有一个集合 \(Y\subseteq X\),一个 \(x\in X\) 存在于 \(Y\) 当且仅当 \(x\) 可达目前已选的某个节点。那么记已选 \(c\) 个数:\((Y,c)\) 可以等价一个局面,即接下来的各选择的方案数构成的集合在 \((Y,c)\) 相等时相等。

然后 dp 是容易的。

接下来考虑复杂度。可以证明:此 DAG 的入度为 \(0\) 的节点数 \(\le 15\)。根据 \(a_i\le 60\) 此为真,读者不妨自证其正确性。

Code:https://www.luogu.com.cn/record/160750270

P8935

你有一棵 \(n\) 个点的根节点为 \(1\) 的有根树,现在你要对这棵树进行剪枝,每次你可以选择一个还未被剪掉的节点 \(u\) 进行操作,然后剪掉 \(u\) 的子树所有点(包括 \(u\))。当且仅当你剪掉 \(1\) 时,操作停止。

你知道 \(1\)\(x\) 这条路径是这棵树的茎,需要特殊处理。所以你需要在第 \(k\) 次剪枝时对 \(x\) 进行操作,而非仅仅将其剪掉,即你不能在第 \(k\) 次及以前对其祖先进行操作使其被连带剪掉。

求有多少种不同的操作序列,两个操作序列不同当且仅当长度不同或存在一次操作 \(i\) 使得两操作序列在第 \(i\) 次时选择的 \(u\) 不同。输出答案模 \(10^9+7\)

\(S\)\(x\) 及其祖先的集合。

\(f(i,j)\)\(i\) 的子树选 \(j\) 次的方案数。容易处理。

\(h(i,j)\)\(i\) 的子树选 \(j\) 次不在 \(S\) 上的点的方案数。容易处理。

\(g(i,j)\) 是留给 \(i\) 的子树去掉 \(S\)\(j\) 次 的方案数(\(i\in S\))。需要求的就是 \(g(x,k-1)\)。沿着 \(S\) 从上往下求。

怎么求:首先可以不操作继承父亲;然后还可以留给下面任意的操作,加上父亲的后缀和。得到目前的 \(g\) 之后直接卷上 \(h\) 即可。

Code:https://www.luogu.com.cn/record/161163464

CF1608F

给定 \(n\)\(k\) 和一个长度为 \(n\) 的整数序列 \(b\)

求有多少个长度为 \(n\) 的序列 \(a\) 满足对于任意的 \(1 \le i \le n\) 都有:

  • \(0 \le a_i \le n\)
  • \(|MEX(a_1,a_2,\dots,a_i)-b_i| \le k\)

其中 \(MEX(c)\) 表示 \(c\) 中没出现过的最小的非负整数。

答案对 \(998244353\) 取模。

\(n \le 2000\) , \(k \le 50\)

\(f(i,j,k)\)\(i\) 位,有 \(j\) 种数大于 \(MEX\)\(MEX\)\(k\) 的方案数。

首先假设这样的状态满足任何一种方案数相等。接下来通过结构归纳来说明这一点是正确的(这是核心?)。

先考虑 \(k\) 不变。那么要么填 \(\le k\),要么 \(>\) 并且没有落在 \(k+1\)

再考虑变化。枚举原来的 \(MEX=k'\),那么有一些大于 \(MEX\) 的数一定在 \([k'+2,k]\) 里面,现在放了 \(k'+1\)。由于归纳假设,可以直接通过 \(j-(k-k'-1)\) 的状态转移。

Code:https://www.luogu.com.cn/record/161285033

CF1466H

\(n\) 个顾客与 \(n\) 个物品,每个顾客有一个排列 \(b_i\) 表示他对物品喜好程度的排名。

你有一个物品分配方案的排列 \(a\),表示 \(i\) 号顾客拿到第 \(a_i\) 个物品。

称一个分配方案 \(a\) 是好的,当且仅当不存在一个非空集合 \(S\),使得存在一个分配方案 \(a'\) 满足:

  1. \(\forall i \in S, a'_i \in S\)
  2. \(\forall i \in S\),第 \(i\) 个顾客相对 \(a_i\) 更喜欢 \(a'_i\)(不要求严格更喜欢 \(a'_i\),即 \(a_i\) 可以等于 \(a'_i\)
  3. \(\exists i \in S\),第 \(i\) 个顾相对 \(a_i\) 严格更喜欢 \(a'_i\)

输入物品分配方案的排列 \(a\),请求出有多少种不同的 \(\{b_1,b_2,\cdots,b_n\}\) 排列组 使得分配方案 \(a\) 是好的。

\(n\le 40\),答案对 \(10^9+7\) 取模。

直接跳到建图:

给定排列 \(p\),求排列族 \(S_{1:n}\) 满足:

黑边 \(i\to j\) 存在当且仅当 \(j\)\(p_i\) 先出现。

白边有 \(i\to p_i\)。任意环不存在黑边。

如何计算方案数?考虑 \(i\) 的黑边连出去的个数 \(d\) 造成的贡献:\(d!(n-d-1)!\)

把置换环缩一下变成点就变成了 DAG。对此进行经典的 DAG 容斥。只需计算一个集合到一个集合的任意连边数的贡献的积和式。这是容易组合计算的。

最后复杂度变成了 \(O(3^n)\)。但是事实上,同一长度环是等价的,只需记录长度为 \(i\) 的环的个数 \(c_i\) 即可。这样的状态是不多的。

Code:https://www.luogu.com.cn/record/161472222

CF1158F

我们定义一个“c序列”为序列里的数都是 \([1,c]\) 的序列。定义一个c序列的“密度”为最大的\(p\),使得任意长度为 \(p\) 的序列(总共 \(c^p\) 个)都是它的子序列。

给定一个长度为\(n\)\(c\)序列,对 \(p\in[0,n]\),求该序列有多少个子序列的密度为 \(p\),mod \(998244353\)

\(n,c<=3000\)

按照 THUSC T2 的结论,就是不断删去包含字符集的前缀。然后 dp 只需要知道:\(f(i,j)\) 表示 \([i,j]\) 中包含 \(i,j\) 的子序列个数,满足 \(a_j\) 只出现了一次。这是容易组合计算的。

但是复杂度是 \(O(n^3/c)\) 的,由于密度小于等于 \(n/c\)。对于过小的 \(c\) 使用 \(O(2^cn^2/c)\) 的状压 dp 即可。于是最后的复杂度就是 \(O(\dfrac{n^3}{\log n})\)

Code:https://www.luogu.com.cn/record/161496914

外包 dp 套 dp

link

Hopcroft

根据之前提到的 Myhill-Nerode 定理的想法,我们来尝试完成划分 DFA 等价类的过程。

主要思想:设 \(S\) 是一个目前还可能被划分的状态集合(等价类)。定义 Split 函数 Split(S)。该函数枚举每个 \(c\in \Sigma\),把 \(S\) 划分为 \(S'_{1:m}\),划分方法是根据 \(c\) 转移到的(当前)等价类是什么划分。

算法主体是一个循环,对于每个当前的等价类调用 Split 函数,直到不能继续划分为止。

我们有更具体的伪代码:

P := {F, Q \ F};
W := {F, Q \ F};
while (W is not empty) do
     choose and remove a set A from W
     for each c in Σ do
          let X be the set of states for which a transition on c leads to a state in A
          for each set Y in P for which X ∩ Y is nonempty and Y \ X is nonempty do
               replace Y in P by the two sets X ∩ Y and Y \ X
               if Y is in W
                    replace Y in W by the same two sets
               else
                    if |X ∩ Y| <= |Y \ X|
                         add X ∩ Y to W
                    else
                         add Y \ X to W
          end;
     end;
end;

这里 \(P\) 就是当前的等价类集合,而 \(W\) 是来执行分裂操作的等价类集合。\(Q\) 是状态集合,\(F\) 是终止态集合,因为接受态和不接受态显然不能合并。

事实上,这里(P := {F, Q \ F},W := {F, Q \ F};)可以被替换成任意的初始划分,包括不划分。在 dp 套 dp 的过程中,我们可以依据题目要求来设置划分,例如在麻将一题中分开乎牌状态与未乎牌,游园会中把不同 popcount 的状态分开(尽管这样会使得几乎无法压缩)。

直接按照伪代码实现是 \(O(n^2\Sigma)\) 的,但是精细地实现(主要是懒惰删除)可以做到 \(O(n\Sigma \log n)\)。具体来说,可以参考 yyyyxh 的实现或者下面麻将一题的提交记录。

Hopcroft 的意义是什么?他把一个较大的自动机的状态数缩小了,通常能缩小不少,从而极大减少程序运行时间(也能代替部分剪枝)。但是说 Hopcroft 得到的结果在 dp 套 dp 中是最优的是不正确的。这是由于,解决这个问题建出来的自动机并非真正要去接受那些字符串,而是起一个结构的作用,因此同样能解决这个问题的自动机可能并不等价。

P5279

今天,治程想要水浒,但是她的朋友们都去上文化课了,因此治程只能自己一个人水。治程找了 zhihu.com,它有 \(n(n\ge 5)\) 种不同的问题,大小分别为 \(1\)\(n\),每种问题都有 \(4\) 个回答。

定义乎乎乎为三张问题编号相同或者大小相邻的回答,即问题编号形如 \(i,i,i(1 \le i \le n)\) 或者\(i,i+1,i+2(1\le i\le n-2)\)。定义乎乎为两个在一个问题底下的知乎回答,即问题编号形如 \(i,i(1 \le i \le n)\)

定义一个回答集合 \(S\) 是乎的当且仅当它的大小为 \(14\) 且满足下面两个条件中的至少一个:

  • \(S\) 可以被划分成五个集合 \(S_1\)\(S_5\) 。其中 \(S_1\) 为乎乎,\(S_2\)\(S_5\) 为乎乎乎。
  • \(S\) 可以被划分成七个集合 \(S_1\)\(S_7\) ,它们都是乎乎,且对应的问题编号两两不同

治程先找到了 \(13\) 张回答,并把剩下的\(4n-13\)张回答随机打乱。

对于一个排列 \(P\),治程定义 \(S_i\) 为治程事先摸出的 \(13\) 张回答加上 \(P\) 中的前 \(i\) 个回答构成的集合,定义 \(P\) 的权值为最小的 \(i\) 满足 \(S_i\) 存在一个子集是乎的。如果你对知乎比较熟悉,不难发现 \(P\) 的权值就是知乎上的中国强大起来的日子。

注意到 \(n\ge 5\) 的时候,\(S_{4n-13}\)总是存在乎的子集的,因此 \(P\) 的权值是良定义的。

现在治程想要训练自己的知乎效率,因此它希望你能先计算出 \(P\) 的权值的期望是多少。

先建立乎自动机,也就是说我假设建立起了内层 dp。

期望转化为 \(\sum P(X\ge i)\),就是 \(i-1\) 次水浒没乎的概率。于是我只需要求出看了 \(j\) 个回答没乎的问题集合数。这样,我可以扫描问题维了。

\(f_{i,j,k}\) 为第 \(i\) 个问题,看了 \(j\) 个回答,目前在乎自动机上的第 \(k\) 节点的方案数。每次转移枚举上一层状态,枚举本次选了 \(l\) 个回答,需要乘上选这个回答的组合数的系数,同时转移到自动机下一个节点。

最大问题是如何建立自动机。设 \(g_{i,j,k,t}\) 为 考虑到 \(i\) 个问题,有 \(j\)\(i\)\(k\)\(i-1\)\(t\) 是是否用了两个相同的回答凑了乎乎,得到了乎乎乎的最大个数。自动机上是不需要 \(i\) 的;忽略 \(i\) 维。

这里,应该有 \(j,k\le 4,gt\le 2\),更多是梅勇的,因为 \(j,k\) 仅仅用于做 \(i,i-1,i-2\) 的乎乎乎类型。这样有 \(50\) 个数,状态就是这样的 \(50\) 元组。还有一个目前回答 \(\ge 2\) 的问题数量,所以是 \(51\) 元组(逆天)。

加入一个数的转移是容易处理的。我们 bfs 找出所有在 \(n\) 次转移之内的可能被访问的 \(51\) 元组,这个数量是不多的。跑 Hopcroft 之后大概只有 800 个,好像也有做到 547 个的做法。

Code:

https://loj.ac/s/2080558(Unhopcrofted)

https://www.luogu.com.cn/record/162066423(Hopcrofted)

事实上加上一点剪枝和内存访问的优化的 Unhopcrofted 代码也可以通过。

P10547

\(n\) 个格子排成一行,从左到右依次编号为 \(1,2,\cdots,n\),每个格子上有一个数字卡片,初始状态下,格子 \(i\) 上的卡片数字为 \(i\)

打乱者会进行 \(n\) 次交换操作来排列这些卡片:每次选择两个格子 \(i,j\)\(i\ne j\)),然后交换格子 \(i\) 和格子 \(j\) 上的卡片。\(n\) 次交换操作结束后,就完成了对卡片的排列。

然后轮到玩家行动,玩家同样需要用交换操作,每次交换两张卡片,目标是将这些卡片的顺序还原到初始状态。

交换格子 \(i\) 和格子 \(j\) 上的卡片所需的时间为 \(|i-j|\),玩家打算用最短的时间还原该排列。问:有多少种可能的排列,玩家可以用不超过 \(m\) 的总时间完成还原?两种排列不同,当且仅当至少有一张数字卡片在两种排列中所在的格子不同。

先考察操作的性质。

注意到若设每个点的势能是 \(|i-p_i|\),一次代价为 \(W\) 的操作的最多使得总势能减少 \(2W\)。因此有不等式:

\[Ans\ge \frac{\sum |i-p_i|}{2} \]

这个形式看起来就很正确。猜想其可以取到下界,所以有:

引理 1:一个排列的最小交换代价是 \(\dfrac{\sum |i-p_i|}{2}\)

证明:

只需说明对于每个非恒等的排列有一个使总势能减少 \(2W\) 的操作即可,然后施加归纳法即可。设原排列为 \(p\),逆排列为 \(r\),则等价于存在:

\[\exists i\neq j,i\le r_j<r_i\le j \]

\(i\) 为最小的 \(i\neq p_i\)\(j\)\([i,r_i]\) 中一个 \(k\) 使得 \(p_k\ge r_i\) 即可。这样的 \(i,j\) 总是存在的。

再考虑“交换 \(n\) 次”是什么意思。不难发现:

引理 2:可以交换 \(n\) 次到达的排列是所有奇偶性等于 \(n\) 的奇偶性的排列。

这是容易证明的:奇偶性不等于 \(n\) 的排列显然无法到达,奇偶性相等的排列可以构造:每次操作直接从后面交换即可(如果需要)。最后剩下的次数是偶数,一直操作 \((1,2)\) 即可。

奇排列和偶排列的答案应该不会差太远,并且应该具有某种模式。打表不难发现:

引理 3:对于 \(\sum |i-p_i|=2k\) 的排列,奇偶排列的个数差的绝对值是 \(\binom{n-1}{k}\),并且正负性是 \((-1)^{n+k}\)

证明(不过显然考试时这个结论是没有必要证明的):考虑建立一个使得势能和不变的奇偶排列的映射。如果存在一个使势能和不变的交换就交换一次,这样的映射显然可逆,这样只需考虑那些不能交换的。

那些不能交换的就是循环都由连续数字构成的排列。设有 \(m\) 个循环,则势能和应该是 \(2(n-m)\),而计数是 \(\binom{n-1}{m-1}=\binom{n-1}{n-m}\)

这里的 DP 采取 ABC134F 的方法。比如这一篇题解。但是那道题的时间复杂度是 \(O(n^2m)\),似乎难以通过。

但是本题具有更特殊的性质:\(m\) 量级小于 \(n^2\)。仔细分析这篇题解的状态,应该有 \(j\)(第二维)是 \(O(\sqrt m)\) 的,只是由于那道题的 \(m=n^2\) 才没有改变复杂度。

这样最后的复杂度就是 \(O(nm\sqrt m)\),可以通过。

Code:https://www.luogu.com.cn/record/162565099

posted @ 2024-06-11 21:13  British_Union  阅读(34)  评论(0编辑  收藏  举报