Loading

近期总结 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)\)

答案为

\[\sum_{j=p}^{r_2} (j-f[j])(g[j]-i) \]

化一下

\[\sum_j j\cdot g[j] -i\sum_j j-\sum_j f[j]\cdot g[j]+i\sum_j f[j] \]

用线段树来做。

每次更新时,发现 \(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\) 的左上角:

\[f_i=\sum_{j,\text{一定条件}} f_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 型”图形有交,并且两个矩形的左上角格子不在同一行也不在同一列。

用式子表示,就是

\[a_i\le c_j<c_i \space \text{且}\space b_j<b_i\le d_j \]

这是二维偏序的形式。按 \(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))\)。。

posted @ 2024-02-14 21:20  Lgx_Q  阅读(8)  评论(0编辑  收藏  举报