「题解」洛谷 P3084 [USACO13OPEN]Photo G


模拟赛做到这个题的时候想用差分约束写个暴力,结果发现其实我根本不会差分约束,于是来浅记一下这道题与差分约束。

由于是在限制区间和为 \(1\),所以容易想到用前缀和来描述这个限制,即为 \(s_r-s_{l-1}=1\),由于 01 序列于是还有 \(0\leq s_i-s_{i-1}\leq 1\),以此得到了 \(s\) 之间的不等式关系,并且知道 \(s_0=0\),那么要求符合条件下 \(1\) 的个数最多,也就是求 \(s_n\) 的最大值。

已知一个变量取值,在差分约束系统中求出其他变量最大值/最小值的方法,可以看。

60 分的差分约束暴力做法:

#include
#include
#include
#include
#include
#include
#include
#include
#define pb emplace_back
#define mp std::make_pair
#define fi first
#define se second
#define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<

现在考虑满分做法:

考虑 dp,设 \(f_i\) 为单独考虑前 \(i\) 个位置,并且 \(i\) 强制选的情况下关键点最多为多少。

(连 dp 都没想到,失败)

那么现在考虑如何判断对于一个 \(j\(f_j\) 能否转移给 \(f_i\),也就是 \(i,j\) 强制为关键点,\((i,j)\) 内的点都不为关键点。

首先,每个区间里最多有一个关键点。对于新加进来的关键点 \(i\),包含它的区间都不能包含 \(j\),所以设包含 \(i\) 的区间左端点最小值为 \(R_i\)(没有则为 \(i\)),那么要满足 \(j

其次,每个区间至少有一个关键点。从 \(f_j\) 转移到 \(f_i\) 时,新的空点是 \((i,j)\),那么就是要求完全在 \(i\) 左侧(因为 \(f_i\) 只需要考虑 \(i\) 左侧的)的区间左端点都 \(\leq j\).所以设完全在 \(i\) 左侧的区间左端点最大值为 \(L_i\)(没有则为 \(0\)),那么要满足 \(L_i\leq j\)

所以 dp 的式子为 \(f_{i}=\max\{f_j+1,L_i\leq j,注意到 \(L\)\(R\) 是有单调性的,完全在 \(i\) 左侧的也一定完全在 \(i+1\) 左侧,包含 \(i\) 的区间左端点一定不会大于包含 \(i+1\) 的区间左端点。所以可以单调队列优化 dp 解决。

时间复杂度 \(\mathcal{O}(n+m)\)