近期总结 2024.2.14
CF1083D The Fair Nut's getting crazy
题意:\(n\) 个数 \(a_{1...n}\),选出两个区间 \([l_1,r_1],[l_2,r_2]\),满足
-
\(l_1<l_2\le r_1<r_2\)
-
对于 \([l_2,r_1]\) 中每个数 \(a_i\),\(a_i\) 在 \([l_1,r_1]\) 和 \([l_2,r_2]\) 中出现次数都恰好 \(1\) 次。
求方案数模 \(10^9+7\)。 \(1\le n\le 10^5,\space a_i\le |10^9|\)
考虑枚举 \(r_1=i\)。
设 \(f[l_2]\) 表示可以选出来的最小的 \(l_1\),\(g[l_2]\) 表示可以选出来的最大的 \(r_2\)。
维护一个数 \(p\),表示 \(l_2\) 最小可以取到 \(p\)。
设 \(a_{r_2}\) 的上一个与其相同的数为 \(a_x\),下一个相同的数为 \(a_y\)。那么更新 \(f[j]\gets \max(f[j],x+1),\space g[j]\gets \min(g[j],y-1)\)。
答案为
化一下
用线段树来做。
每次更新时,发现 \(f\) 单调递减,\(g\) 单调递增,二分 + 区间覆盖即可。
\(O(n\log ^2n)\).
AGC031E Snuke the Phantom Thief
题意:平面上有 \(n\) 个点,每个点坐标 \((x_i,y_i)\),以及权值 \(v_i\)。选一些点,满足选出来的点的权值总和最大,但是有 \(m\) 个限制,每个限制形如:
-
横坐标 \(\le a_i\) 的点最多选 \(b_i\) 个
-
横坐标 \(\ge a_i\) 的点最多选 \(b_i\) 个
-
纵坐标 \(\le a_i\) 的点最多选 \(b_i\) 个
-
纵坐标 \(\ge a_i\) 的点最多选 \(b_i\) 个
\(1\le n\le 80,\space 1\le x_i,y_i,a_i\le 100,\space 1\le v_i\le 10^{15},\space 1\le m\le 320\)
网络流。
但是有四个限制,很不好处理。但是我们知道,如果只有横纵两个限制,可以转化为二分图的东西。
比如横坐标限制有两种,我们考虑转化,如果知道一共选择的点数 \(k\),则 “横坐标 \(\ge a_i\) 的点最多选 \(b_i\) 个” 的限制转为 “横坐标 \(\le a_i\) 的点最少选 \(b_i\) 个”。
枚举 \(k\),然后发现 “横坐标 \(\ge a_i\) 的点最多选 \(b_i\) 个” 相当于横坐标第 \(a_i+1\sim k\) 大的点的横坐标 \(>a_i\)。
分开横纵坐标,比如横坐标,算出第 \(1\sim k\) 大的点的横坐标取值范围。
建立关于横坐标的点 \(1\sim k\),对于 \(i\),设其横坐标取值范围为 \([l,r]\),那么枚举 \(n\) 个点中哪些满足条件,比如点 \(j\),然后连一条边 \(i\to j\),容量为 \(1\),费用为 \(0\)。
纵坐标则 \(j\to i\)。为了保证一个点最多选一次,拆点,拆出来的两个点连边,容量为 \(1\),费用为 \(v_i\)。
可以发现这样连边一定满足限制。
跑最大费用最大流,当最大流为 \(k\) 时更新答案。
CF720D Slalom
题意:一个 \(n\times m\) 的网格,有 \(k\) 个矩形障碍,保证这些障碍不重叠,但可能接壤。
从 \((1,1)\) 走一条路径,每次只能向右或向上,把 \(k\) 个矩形划分成两个集合,求有多少种可能的划分方法,模 \(10^9+7\)。
\(3\le n,m\le 10^6,\space 1\le k\le 10^5\)
一个直观的独特的方法。
注:下文认为横坐标为行的编号,纵坐标为列的编号。
考虑类似于 这题 的思想,我们计算 跨越在下面的矩形的集合上方的轮廓线个数,这样可以做到每个集合算一次。
例如
其特点是:每次从上到右的拐弯都会在与这条轮廓线接壤的矩形的左上角处。
因此,我们可以在每个矩形的左上角处做 dp,设 \(f_i\) 表示从 \((1,1)\) 到矩形 \(i\) 的左上角处的轮廓线个数。
转移枚举上一个矩形 \(j\) 的左上角:
现在我们分析“一定条件”是什么,不难发现,从矩形 \(j\) 的左上角拐弯后,轮廓线会在矩形 \(j\) 的上面一行向左走,然后在矩形 \(i\) 的左边一列向上走,条件就是走到的格子没有障碍。
考虑算出从矩形 \(i\) 的左上角处开始,向下/向右一直走空格子,最远能走到的格子 \((a_i,b_i),(c_i,d_i)\),如下图
那么矩形 \(j\) 上面的 \((c_j,b_j)\sim (c_j,d_j)\) 都是空格子,矩形 \(i\) 左边的 \((a_i,b_i)\sim (c_i, b_i)\) 都是空格子。
我们可以理解为每个矩形都对应一个这样的“L 型”图形,因此 \(j\) 能转移到 \(i\) 的条件是这两个“L 型”图形有交,并且两个矩形的左上角格子不在同一行也不在同一列。
用式子表示,就是
这是二维偏序的形式。按 \(b_i\) 排序,由于有 \(d_j\) 的限制,每个决策 \(j\) 贡献到后面的 \(i\) 是从 \(j+1\) 开始的一段,这个可以二分/优先队列处理。然后 \(a_i\le c_j<c_i\) 可以直接用树状数组/线段树查询 \([a_i,c_i-1]\) 的和。
边界情况可以在网格下面增添一个矩形表示起点,在网格右边增添一个矩形表示终点。
最后一个问题:如何求 \(a_i,b_i,c_i,d_i\)?
首先 \(b_i,c_i\) 是已知的,就是矩形左边一列和上面一行的编号。以 \(a_i\) 为例,\(d_i\) 类似。
我们要求的就是“从 \((c_i,b_i)\) 向下走,走到的第一个有障碍的格子的坐标”。考虑从前往后扫描线,并用 multiset 储存每个扫到的矩形对应的线段的上端点。每次先查询 \((c_i,b_i)\) 是否为空,若为空,查询 set 中 \(c_i\) 的前驱即为所求。
时间复杂度 \(O(k\log (n+m+k))\)。。