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

细节见其他题解。

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

DP(优化)的更多相关文章

  1. NOIP2015 子串 (DP+优化)

    子串 (substring.cpp/c/pas) [问题描述] 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个 互不重 叠 的非空子串,然后把这 k 个子串按照其在字 ...

  2. LCIS tyvj1071 DP优化

    思路: f[i][j]表示n1串第i个与n2串第j个且以j结尾的LCIS长度. 很好想的一个DP. 然后难点是优化.这道题也算是用到了DP优化的一个经典类型吧. 可以这样说,这类DP优化的起因是发现重 ...

  3. 取数字(dp优化)

    取数字(dp优化) 给定n个整数\(a_i\),你需要从中选取若干个数,使得它们的和是m的倍数.问有多少种方案.有多个询问,每次询问一个的m对应的答案. \(1\le n\le 200000,1\le ...

  4. dp优化1——sgq(单调队列)

    该文是对dp的提高(并非是dp入门,dp入门者请先参考其他文章) 有时候dp的复杂度也有点大...会被卡. 这几次blog大多数会讲dp优化. 回归noip2017PJT4.(题目可以自己去百度).就 ...

  5. loj6171/bzoj4899 记忆的轮廊(期望dp+优化)

    题目: https://loj.ac/problem/6171 分析: 设dp[i][j]表示从第i个点出发(正确节点),还可以有j个存档点(在i点使用一个存档机会),走到终点n的期望步数 那么 a[ ...

  6. 常见的DP优化类型

    常见的DP优化类型 1单调队列直接优化 如果a[i]单调增的话,显然可以用减单调队列直接存f[j]进行优化. 2斜率不等式 即实现转移方程中的i,j分离.b单调减,a单调增(可选). 令: 在队首,如 ...

  7. 【学习笔记】动态规划—各种 DP 优化

    [学习笔记]动态规划-各种 DP 优化 [大前言] 个人认为贪心,\(dp\) 是最难的,每次遇到题完全不知道该怎么办,看了题解后又瞬间恍然大悟(TAT).这篇文章也是花了我差不多一个月时间才全部完成 ...

  8. Codevs 1305 Freda的道路(矩阵乘法 DP优化)

    1305 Freda的道路 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description Freda要到Rainbow的城堡去玩了.我们可以认 ...

  9. [总结]一些 DP 优化方法

    目录 注意本文未完结 写在前面 矩阵快速幂优化 前缀和优化 two-pointer 优化 决策单调性对一类 1D/1D DP 的优化 \(w(i,j)\) 只含 \(i\) 和 \(j\) 的项--单 ...

  10. hdu1505 暴力或dp优化

    题意:        给你一个矩阵,让你在里面找到一个最大的f矩阵.. 思路:       三种方法ac这到题目;  方法(1) 以宽为主,暴力    开一个数组sum[i][j],记录当前这个位置的 ...

随机推荐

  1. JVM源码分析-Java运行

    最近在看Java并发编程实践和Inside JVM两本书,发现如果不真正的了解底层运作,那么永远是雾里看花.因此从http://openjdk.java.net/groups/hotspot/上下载了 ...

  2. spring gateway 学习

    为什么需要使用网关 1.实现统一认证 2.统一一个域名,解决调用困难. 3.协议转换 将不友好的协议转成友好的协议. spring cloud gateway 是什么 是spring cloud 的第 ...

  3. WebSocket事件

    优点 双通信,减少延迟 四个主要的Web Socket API事件: ·打开 onopen 当在客户端和服务器建立连接,就会从Web Socket实例触发open事件.它被称为客户端和服务器之间的初始 ...

  4. Qt tr 无法翻译

    项目中碰到部分tr无法翻译的问题,最后发现由于继承QObject的子类没有加上Q_OBJECT宏.

  5. MySQL 8.0 相对于 MySQL 5.7

    MySQL 8.0 相对于 MySQL 5.7,有很多新特性,比如:快速加列.原子 DDL.不可见索引.额外端口.角色管理等.这一节内容,就不讲这些新特性了,只来聊聊最近在工作学习过程中遇到的几处细节 ...

  6. shell中字符串比较和模糊比较说明

    shell字符串比较说明 1 完全比较方法(完全匹配) if [ "$soure" == "$dest" ]; then echo "is ==&qu ...

  7. 用EwoMail开源版搭建邮箱服务器

    介绍: EwoMail是基于Linux的开源邮件服务器,支持一键搭建,集成了众多优秀稳定的组件,是一个快速部署.简单高效.安全稳定的邮件解决方案,支持电脑和手机的客户端,适合个人或邮箱功能需求少的企业 ...

  8. Qt编写物联网管理平台40-类型种类

    一.前言 为了增强本系统的拓展性,做成通用的物联网管理平台,特意将控制器主设备类型.探测器子设备类型.对应种类符号等信息,全部做成表格可自定义添加和修改,这样在控制器信息表和探测器信息表管理的时候,可 ...

  9. Qt通用方法及类库10

    函数名 //获取保存的文件 static QString getSaveName(const QString &filter, QString defaultDir = QCoreApplic ...

  10. [转]实体类与数据库字段不匹配问题,java.sql.SQLSyntaxErrorException: Unknown column 'xxx' in 'field list'

    控制台报错 ### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'user_nam ...