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)\),就有
先考虑 \(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\),其带的权应为:
考虑拆一下贡献。
把到叶子的线延长划分出若干区域。把每个区域内的贡献乘起来就可以了。
中间的那些点一定是在树上的路径(判断时有一些细节,不是半平面交起来!)。直接乘起来即可。这样,就解决了计算权值的问题。
还需要知道:哪些点对有贡献?即哪些点对可能成为相邻的叶子?显然,树上路径点必须在连边的一侧(不妨统一设为左侧),然后根据原树上边转移才能保证没有问题。具体来说,不是按照叶子转移,而是先对子树内的边标号,双向边两个方向不同,然后按照相邻叶子在原树上的起始边转移。
这里的转移类似于 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'\) 满足:
- \(\forall i \in S, a'_i \in S\)
- \(\forall i \in S\),第 \(i\) 个顾客相对 \(a_i\) 更喜欢 \(a'_i\)(不要求严格更喜欢 \(a'_i\),即 \(a_i\) 可以等于 \(a'_i\))
- \(\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
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\)。因此有不等式:
这个形式看起来就很正确。猜想其可以取到下界,所以有:
引理 1:一个排列的最小交换代价是 \(\dfrac{\sum |i-p_i|}{2}\)。
证明:
只需说明对于每个非恒等的排列有一个使总势能减少 \(2W\) 的操作即可,然后施加归纳法即可。设原排列为 \(p\),逆排列为 \(r\),则等价于存在:
取 \(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