杂题选做3
杂题选做3
QOJ2618
三个节点还是不好做,考虑仅有两个节点 \(x_1,x_2\) 该怎么做?
我们可以使用动态规划法来解决这个问题:设 \(f_{i,j}\) 表示还有 \(j\) 秒,此刻 \(x_1-x_2=i\) 的概率,转移可以枚举当前会发生的每一种状态:
整合一下:
居然和 \(p\) 没关系,确实没关系。
但是这样直接做是 \(O(nk)\) 的,怎么办呢?发现这个转移明显是很多个多项式卷积得来的,分治fft优化一下既可以做到 \(O(n \log n)\) 。
现在有三个点 \(x_1,x_2,x_3\) ,该怎么办呢?发现这三个点之间的距离就是 \(x_1,x_2\) 的距离加上 \(x_1,x_3\) 的距离加上 \(x_2,x_3\) 的距离然后除二即可。所以解决了两个点就可以解决三个点。
时间复杂度 \(O(n \log n)\) 。
QOJ2605
逆天构造题。
合法点集的要求有点像选出二分图的左部和右部点,我们先对原图构造一张至少有 \(nk\) 条边的二分图:
按照编号从小到大进行二分图染色。对于节点 \(u\) ,仅考虑 \(v<u\) 且 \((u,v)\) 有边的节点 \(v\) 构成的集合 \(s\) 。如果 \(s\) 中的点在二分图的左部更多,则将 \(u\) 放入二分图的右部;反之放入左部。
容易发现这样的构造,二分图的边数不会小于 \(\frac{m}{2}\) ,也就是 \(nk\) 。
接下来我们找到度数小于等于 \(k\) 的点,删除,一直循环直到所有节点度数都大于 \(k\) ,此时就是一组解。一个比较平凡的实现就是使用set维护所有节点的度数,然后每一次取出度数最小点进行修改一类,时间复杂度为 \(O((n+m) \log n)\) ;但是注意到,如果一个节点 \(u\) 的删除导致某些节点度数小于等于 \(k\) 了,那一定是与 \(u\) 直接相邻的节点,所以使用一个队列维护即可,时间复杂度为 \(O(n+m)\) 。
但是有没有一种可能,我们上面的流程把图删空了呢?其实是不可能的,假设当前还有 \(n\) 个点和至少 \(nk\) 条边,因为我们只会删除度数小于等于 \(k\) 的点,所以进入 \(n-1\) 个点的时候,也有至少 \((n-1)k\) 条边。我们归纳的证明,上述流程结束之前的任何时刻,假设目前有 \(n\) 个节点,就一定有至少 \(nk\) 条边。因为一定存在某一个时刻 \(nk>\frac{n(n-1)}{2}\) ,所以不会被删空。
QOJ1243
画图发现不会存在两个点 \(p,q\) ,两点均不是矩形的四个角。所以至多只有一个节点 \(p\) 不是矩形的四个角。我们枚举 \(p\) ,剩下的点只会出现在左对角/右对角中。分类讨论每一个矩形对 \(p\) ,左对角,右对角的覆盖情况:
- 仅覆盖 \(p\) ,可以放入左对角和右对角。
- 覆盖 \(p\) ,左对角,可以放入右对角。
- 覆盖 \(p\) ,右对角,可以放入左对角。
- 仅覆盖左对角,可以放入 \(p\) 或者右对角。
- 仅覆盖右对角,可以放入 \(p\) 或者左对角。
- \(p\) ,左对角和右对角都没有覆盖,可以放入 \(p\) 或者左对角或者右对角。
我们可以枚举上述 \(24\) 种情况进行计算。左右对角也分(左下角和右上角,左上角和右下角),所以一共 \(48\) 种情况。时间复杂度 \(O(XY+n)\) 。
QOJ7254
肯定考虑dp,关键在于如何去重。我们设 \(f_{i,j}\) 表示考虑 \(a\) 序列长度为 \(i\) 的前缀和 \(b\) 序列长度为 \(j\) 的前缀合并,可以得到多少种完全不同的序列。
一个最为基本的转移就是 \(f_{i,j}=f_{i-1,j}+f_{i,j-1}\) 。
这样算重复的原因就是,可能存在 \(a[1\dots i]\) 和 \(b[1\dots j]\) 的一个长度为 \(k\) 的公共后缀。假设取完了 \(a[1\dots i-k]\) 和 \(b[1\dots j-k]\) ,这样的后缀会使得答案算多因为可以让 \(a\) 和 \(b\) 的操作交换。
得到一个转移:
但是这样依然不对。假设取出了两个完全相同的,长度为 \(p\) 的后缀,也可能在转移过程中到达某一个状态 \(f_{i-q,j-q}\) ,其中 \(q<p\) 但是也是 \(a[1\dots i],b[1 \dots j]\) 的公共后缀。我们可以直接使用卡特兰数避免这种情况(折线图不允许触碰 \(x=y\))。
得到转移:
最后分析一下时间复杂度,是 \(O(n^3)\) 吗?不对,因为排列的限制,所以对于一个前缀 \(a[1\dots i]\) ,仅有一个前缀 \(b[1\dots j]\) 满足 \(\text{lcs}(i,j) \neq 0\) ,所以时间复杂度应该是 \(O(n^2)\) 。
QOJ7308
打表发现:\(f_1=1,f_2=2,f_3=6,f_4=16\) 。
对于 \(n>4,f_n=2f_{n-1}+f_{n-3}+2\) ,使用矩阵优化。时间复杂度 \(O(T \log n)\) 。
QOJ1087
首先,这种二进制问题是优先考虑拆位的。我们看看这个问题在每一个二进制位的体现:
你需要给每一个位置赋予一个 \(01\) 权值,要求某些区间的权值全部是 \(1\);某些区间的位置中至少存在一个 \(0\) 。
先不考虑删除第 \(i\) 的限制的影响,对原问题求出是否有解。我们将“要求区间内部全是 \(1\)” 的限制优先考虑,先对 \(l_i,r_i\) 做区间覆盖,获得数组 \(a\) 。然后检录 “要求区间内部至少存在一个 \(0\)” 的限制的合法性。
现在讨论删除某一个限制的影响,根据删除的限制的种类分讨:
-
删除的是“要求区间中间至少存在一个 \(0\)”的限制,那么对于 \(a\) 不会有任何改变。如果本身不合法的区间只有这一个,那么删除之后整个局面就会变得合法起来。
-
删除的是“要求区间中间全部都是 \(1\)”的限制,那么会导致某一些 \(a_i\) 从 \(1\) 变成 \(0\) ,哪些位置会从 \(1\) 变成 \(0\) ?就是被覆盖了恰好一次的位置,我们可以对于每一个限制,求出被 \([l_i,r_i]\) 覆盖,且仅被 \([l_i,r_i]\) 覆盖的下标集合 \(s\) 。
具体而言,先求出每一个位置的覆盖次数,然后寻找 \([l_i,r_i]\) 内仅被覆盖一次的位置,可以使用并查集之类的算法找到。
接下来,将 \(s\) 排序后得到数组 \(b\) 。认为 \(b_0=0,b_{|s|+1}=n+1\) 。如果存在某一个不合法的区间 \([l,r]\) ,满足 \(\forall i \in [0,|s|] ,b_i<l \leq r<b_{i+1}\) ,那么就说明这个区间内部依然全部是 \(1\) 。
我们考虑枚举每一个 \(i\) ,然后查询是否有区间被 \((b_i,b_{i+1})\) 包含,显然可以使用一个线段树维护。
时间复杂度 \(O(n \log n \log V)\) 。