20250224
D. 01 串
没场切的 T1。
statement
给定由 \(01\) 构成的长度为 \(n\) 的初始串 \(a_i\) 和目标串 \(b_i\),有三种操作:
- \(0\) 变 \(1\),代价为 \(t_0\);
- \(1\) 变 \(0\),代价为 \(t_1\);
- 交换相邻位置的值,代价为 \(t_s\)。
多测,\(1 \le \sum n \le 4 \times 10^6\),2000 ms。
solution
比较显然的 Observation:
- 交换只会交换不同的数。
- 同时对一个位置进行取反和交换不优。
考虑 dp,设 \(f(x)\) 为前 \(x\) 个完成变换的代价,\(f(0) = 0\)。
- 自己直接变,\(f(x) = f(x-1) + cost(a_x, b_x)\),\(cost(u, v)\) 为 \(u\) 变成 \(v\) 的代价。
- 有一段进行交换:
- 找到最大的 \(y\) 使得 \((y, x]\) 中 \(\sum a_i = \sum b_i\);
- 这一段中 \(1\) 一定是朝同一个方向移动,否则可从中间某个位置断开;
- 所以 \(f(x) = f(y) + t_s * |\sum_{y < i \le x} (a_i - b_i) \times i|\)。
两种情况取 \(\min\) 即可。
代码中 pos[i] 是一个封装的平移坐标轴的数组,下标可以为负数。
\(O(n)\)。
for (int i = -N; i <= N; ++i) pos[i] = -1;
pos[0] = 0;
for (int x = 1; x <= N; ++x) {
s1[x] = s1[x - 1] + (a[x] - b[x]), s2[x] = s2[x - 1] + (a[x] - b[x]) * x;
f[x] = f[x - 1] + cost(a[x], b[x]);
int y = pos[s1[x]];
if (~y) f[x] = min((LLL)f[x], f[y] + (LLL)CS * abs(s2[x] - s2[y]));
pos[s1[x]] = x;
}
G. 小学生博弈题
水题。
statement
给定一个 \(n \times n\) 的方阵,第 \(i\) 行的 \([L_i, R_i]\) 内为 \(1\),其他位置为 \(0\)。求它的行列式。
多测,\(1 \le \sum n \le 1.5 \times 10^6\),1000 ms。
solution
使用左偏树模拟高斯消元即可,记录节点对应的行号和行号对应的节点,方便维护符号。
\(O(n \log n)\)。
QOJ 2812 Paths
水题。
statement
给定一棵 \(n\) 个点的树,边带权。对于每个 \(x \in [1, n]\),选 \(k\) 个节点,使得 \(x\) 到这 \(k\) 个关键节点的路径交最长。\(k\) 为给定常数。
\(1 \le n \le 10^5\),300 ms。
solution
显然长剖取前 \(k\) 长链。
换根时,把父亲连儿子的边的权值,从儿子的长链中减掉,加到父亲连向当前儿子之外的最长链上。
前 \(k\) 大使用对顶堆维护即可。
\(O(n \log n)\)。
B. 小 ds,确信
数据结构:线段树
problem
给定四个长度为 \(n\) 的序列 \(a_i\),\(b_i\),\(c_i\),\(d_i\)。
将 \(U = \{1, 2, 3, \dots, n\}\) 划分成两个非空子集 \(S\) 和 \(T\),最小化:
多测,\(1 \le \sum n \le 10^6\),1500 ms。
solution
考虑扫描线,钦定前两个,维护后两个,在此过程中寻找最小值。
具体地,从大到小枚举 \(\max a_x\),线段树上每个节点维护 \(\max b_x = i\) 时 \(\max b_x + \max c_y + \max d_y\) 的值,维护区间最小值。
将一个元素由 \(S\) 移动到 \(T\) 时,因为 \(c\) 和 \(d\) 要对当前值取 \(\max\),由于单调性,恰有一段后缀需要区间推平,使用线段树二分找到开始的位置。
要求非空子集,可以再开一棵线段树,维护当前已经确定的 \(\max a_x\) 下,合法的 \(\max b_x\) 位置,容易发现这是一个区间,线段树二分即可。
\(O(n \log n)\)。
SPOJ MUZIDA - Muzidabutur
非常好线性代数。
statement
给定一个长度为 \(n\) 的序列 \(a_i\),且 \(\forall 1 \le i \le n, 0 \le a_i \le 25\)。
\(q\) 组询问,每次给定 \(l\),\(r\),求区间 \([l, r]\) 本质不同子序列。答案对 \(10^9+7\) 取模。
\(1 \le n, q \le 10^6\),1000 ms。
solution
有个显然的 DP:
设 \(f(i, j)\) 为前 \(i\) 个数构成以 \(j\) 结尾的子序列方案数。
直接建线段树暴力矩阵乘法是 \(O(nm^3+qm^2\log n)\) 的。
可以多加入一行列表示当前所有的和,那么对这个矩阵减去单位矩阵之后只有 \(6\) 个位置非 \(0\)。
拿这几个位置进行矩阵乘法单次乘法为 \(O(m)\)(\(m\) 为字符集大小)。
满秩可逆,于是可以用前 \(l-1\) 的逆乘上前 \(r\) 的矩阵,然后常数对应的行 \(sum\) 对应的列上的数即为所求。
逆矩阵乘起来的时候可以转置一下。
因为只关心“常数对应的行 \(sum\) 对应的列上的数”,所以单次询问为 \(O(m)\) 的。
\(O((n + q)m)\)。
简单题结束,下面为毒瘤。
C. 形式化题面
分块
statement
一个初始为空的序列,进行 \(q\) 次操作:
1 x在末尾加入 \(x\)。2 x询问当前序列中长度为 \(x\) 的区间 价值 之和。
定义区间 \([l, r]\) 的 价值 为区间中前 \(k\) 的的数的乘积。\(k\) 为给定常数。
任意时刻序列中所有数互不相同。
强制在线,\(1 \le q \le 2 \times 10^5\),\(1 \le k \le 200\)。
solution
这题有点复杂,可以分成两步。
- 把原题转化成二维平面上的 \(O(qk)\) 次操作。
- 使用数据结构维护各个时刻历史距离右端点距离为 \(len\) 的值。
转化
维护每个时刻 \(x\) 到当前右端点 \(n\) 的前 \(k\) 大的乘积 \(f(x)\) 以及后缀第 \(k\) 大 \(v(x)\)(不足 \(k\) 个取最小值)。
设从 \(x\) 开始的后缀前 \(k\) 大构成的集合为 \(S(x)\)。
同一时刻,显然 \(f(x)\) 和 \(v(x)\) 非严格单调递减。
不难发现,\(S(x)\) 相同的段构成一些区间。
\(S(x) \neq S(x+1)\) 当且仅当 \(a_x \in S(x)\)。因此 \(a_x\) 被移除 \(S(x)\) 之后 \(x\) 所在的段就可以和 \(x+1\) 所在的段合并。
记 \(T = \{x | S(x) \neq S(x+1)\}\)。使用链表维护 \(T\)。
进一步,\(|S(x) \cap S(x+1)| \ge n - 1\),一个位置只有一个数,不可能同时塞两个进去。
于是 \(S(x) \subseteq \{a_y | y \in T \land y \ge x\}\)。
\(S(x)\) 要变化,当且仅当 \(a_n > v(x)\)。变化的是一段后缀。
若 \(n - x + 1 \le k\),则直接加入 \(S(x)\)。
若 \(v(x) = a_x\),则本轮过后 \(x\) 应从 \(T\) 中删除。
对于最小的 \(x\) 使得 \(a_n > v(x)\),\(v(x)\) 更新为 \(\min_{y \ge x, y \in T, a_y > v(x)} \{a_y\}\)。
否则令 \(y\) 为删除之前 \(x\) 的前驱。若 \(y\) 要被删除,新的 \(v(x)\) 为新的 \(v(y)\)(合并了),否则为旧的 \(v(y)\)(旧的 \(v(y)\) 也是 \([x, n-1]\) 中的第 \(k-1\) 大)。
同时维护 \(f(x)\),显然同一段的 \(f(x)\) 会增加同一个值。
考虑这样做的复杂度:若 \(a_x > a_n\),对 \(n\) 只会发生至多 \(k\) 次;若 \(a_x < a_n\),对 \(x\) 只会发生至多 \(k\) 次。操作次数均摊 \(O(qk)\)。
分块维护
以 \(n - x\) 为横轴,\(x\) 为纵轴,建立平面直角坐标系。(修改与 \(x\) 有关,查询与 \(n - x\) 有关。)
一次修改可以看成图中的浅蓝色梯形部分,可以看成大的矩形减去黄色三角形加上粉色三角形。
询问形如如图所示的几种线段所覆盖的区域之和,且一端一定不在 \(n\) 的下面。
线段转化成点,矩形加转化成纵轴区间加一次函数。三角形加直接在横轴上加即可(之后不会访问三角形里面的点)。
使用分块平衡复杂度,\(O(1)\) 修改,\(O(\sqrt q)\) 查询。
总复杂度 \(O(q(k + \sqrt q))\)。

浙公网安备 33010602011771号