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)\) 的最大收益。

从左到右考虑,当一个解锁可以用的时候我们将其加入影响。

维护两个值,mxva,前者表示当前所有可用的影响中最大的 \(-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 ;
}
posted @ 2022-03-10 15:04  Kamiya-Kina  阅读(86)  评论(0编辑  收藏  举报