CF1648 题解
Preface
题解合集。
Main
A. Weird Sum
给定一个 \(n\times m\) 的矩阵,每一个格子有一个颜色,求所有相同颜色的格子对的哈夫曼距离之和。
\(\texttt{data range:} n\times m \leq 10^5\)。
行列可以分开做,每一个颜色也可以分开做,对单个颜色排序之后一维的情况是容易求解的。
B. Integral Array
给一个长度为 \(n\) 的序列,最大的元素不超过 \(c\),对于这个序列中的某一个元素 \(x\),要求所有的 \(y\leq x\) 都满足 \(\left\lfloor\dfrac{x}{y}\right\rfloor\) 都在这个序列中,判断这个序列是否合法。
\(\texttt{data range:} n,c\leq 10^6\)。
从小往大考虑,去重之后考虑当前元素可以拓展多少个元素,也就是有多少元素除去某一个元素 \(y\) 之后可以成为当前元素,所以枚举每一个元素来拓展,由于我们是乘法,而且每一个都不相同,所以时间复杂度是调和级数 \(O(n\lg c)\) 的,可以通过。
C. Tyler and Strings
给定两个字符串 \(s,t\),\(n = |s|, m = |t|\),求将 \(s\) 重排之后字典序比 \(t\) 小的所有本质不同 \(s\) 的方案数,对 \(998244353\) 取模。
\(\texttt{data range:} n,m\leq 2\times 10^5\)。
我们考虑 \(s\) 和 \(t\) 前 \(i-1\) 个字符都是相同的,考虑第 \(i\) 个字符的情况,要不就继续和 \(t\) 相等,要不就比 \(t\) 小,所以我们计算一次比 \(t\) 下的贡献,我们设现在剩下的字符种类数为 \(k\),字符 \(j\) 的数量为 \(cnt_j\),那么我们此时的贡献明显就是 \(\sum\limits_{j< t_i}\dfrac{(n-i)!}{\prod\limits_{d\neq j} cnt_d!}\dfrac{1}{(cnt_j-1)!}\),我们可以通过维护 \(\dfrac{cnt_j!}{(cnt_j-1)!}\) 的前缀和还有 \(\prod\limits_{j}\dfrac{1}{cnt_j!}\) 来查询,前者可以用树状数组来维护,总时间复杂度 \(O(n\lg n)\)。
注意最后要考虑 \(n<m\) 并且 \(s\) 是 \(t\) 的一个前缀的情况,还要取模。
D. Serious Business
给定一个 \(3\times n\) 的矩形空间,第一、三行可以随便走,第二行需要解锁之后才能走,一共 \(q\) 个解锁,第 \(i\) 个解锁可以解锁 \([l_i,r_i]\) 范围,但是需要花费 \(k_i\) 的贡献,求从 \((1,1)\) 走到 \((3,n)\) 的最小花费。
\(\texttt{data range:} 1\leq n,q\leq 5\times 5\times 10^5\)。
令 \(s_i\) 表示 \(\sum\limits_{j=1}^ia_{1,j}\)
考虑维护从 \((1,1)\to (2,i)\) 的最大收益。
从左到右考虑,当一个解锁可以用的时候我们将其加入影响。
维护两个值,mx
和 va
,前者表示当前所有可用的影响中最大的 \(-k_i\) 的值,后者表示答案。
此时加入一个解锁,可以从两个地方得到转移,就是上一个最大的答案减去当前的 \(k_j\) 或者 \(s_i\) 减去当前的 \(k_j\)。
维护答案用线段树或者平衡树都可以。
const int N = 5e5 + 10;
const ll INF = 1e18;
int n, q;
int a[4][N];
int L[N], R[N], K[N];
ll s[4][N];
vector <int> add[N];
vector <int> del[N];
struct SegMentTree {
#define ls o << 1
#define rs ls | 1
ll va[N << 2], mx[N << 2], tg1[N << 2], tg2[N << 2];
inline void psu(int o) {
va[o] = max(va[ls], va[rs]);
mx[o] = max(mx[ls], mx[rs]);
}
inline void ps1(int o, ll k) {
tg1[o] += k, tg2[o] += k;
va[o] += k;
}
inline void ps2(int o, ll k) {
cmax(va[o], k + mx[o]);
return cmax(tg2[o], k);
}
inline void psd(int o) {
ps1(ls, tg1[o]), ps1(rs, tg1[o]), tg1[o] = 0;
ps2(ls, tg2[o]), ps2(rs, tg2[o]), tg2[o] = -INF;
}
void bld(int o, int lef, int rig) {
mx[o] = va[o] = tg2[o] = -INF;
if(lef == rig) return ;
int mid = (lef + rig) >> 1;
bld(ls, lef, mid), bld(rs, mid + 1, rig);
return psu(o);
}
void upd(int o, int lef, int rig, int k, ll x, ll y) {
if(lef == rig) {
va[o] = x, mx[o] = y;
return ;
}
int mid = (lef + rig) >> 1;
psd(o);
if(k <= mid) upd(ls, lef, mid, k, x, y);
else upd(rs, mid + 1, rig, k, x, y);
return psu(o);
}
} T;
inline void solve() {
n = rd, q = rd;
for(int i = 1; i <= 3; i++) {
for(int j = 1; j <= n; j++) {
s[i][j] = a[i][j] = rd;
s[i][j] += s[i][j - 1];
}
}
for(int i = 1; i <= q; i++) {
L[i] = rd, R[i] = rd, K[i] = rd;
add[L[i]].push_back(i);
del[R[i] + 1].push_back(i);
}
T.bld(1, 1, q);
ll ans = -INF;
for(int i = 1; i <= n; i++) {
ll tem = max(T.va[1], s[1][i]);
dbg(T.va[1]);
for(int x : add[i])
T.upd(1, 1, q, x, tem - K[x], -K[x]);
T.ps2(1, s[1][i]);
T.ps1(1, a[2][i]);
for(int x : del[i])
T.upd(1, 1, q, x, -INF, -INF);
// dbg(T.va[1]);
dbg(s[3][n] - s[3][i - 1]);
cmax(ans, T.va[1] + s[3][n] - s[3][i - 1]);
}
cout << ans << '\n';
return ;
}