1 条题解

  • 0
    @ 2025-8-24 22:50:00

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Alex_Wei
    **

    搬运于2025-08-24 22:50:00,当前版本为作者最后更新于2023-09-10 18:54:05,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P9600 [IOI2023] 封锁时刻

    dxidx_i 表示 XXii 的距离,dyidy_i 表示 YYii 的距离。

    一个原始的想法:显然地,cic_i 只会取到 dxidx_idyidy_i。如果 ci=min(dxi,dyi)c_i = \min(dx_i, dy_i),那么它对答案贡献 11;如果 ci=max(dxi,dyi)c_i = \max(dx_i, dy_i),那么它对答案贡献 22。这样问题转化为了非常经典的 Cardboard Box:枚举被取到的最大的 bib_i,那么所有 bk<bib_k < b_ikk 至少取也会取 aia_i。将 bb 从小到大排序,枚举 ii,设 SS1ki1\leq k\leq ibkakb_k - a_ki<kni < k \leq naka_k 构成的可重集,求出最大的 jj 使得 SS 的前 jj 小的元素之和加上 k=1iak\sum_{k = 1} ^ i a_k 不超过 KK。将所有 aia_ibiaib_i - a_i 离散化后 BIT 上二分即可。

    然而直接这样做是有问题的:城市 iiXX 可达的前提条件是 XXii 所有城市均可达,也就是 iiXX 方向上的后继 s(i,X)s(i, X) 可达。我们求出的方案不一定能满足限制。来看看什么样的贡献是不符合限制的吧:

    • 先把后继不存在的情况考虑掉:不妨设 i=Xi = X。设 j=s(i,Y)j = s(i, Y)。如果 ci=0c_i = 0,那么它产生的 11 的贡献显然合法。如果 ci=dyic_i = dy_i,则要求 cjdyjc_j \geq dy_j。因为 dyi>dyjdy_i > dy_j,所以如果 cj<dyjc_j < dy_j,那么令 cjc_j 变成 dyjdy_j(增加至少 11 贡献,增加至多 dyjdy_j 代价),cic_i 变成 00(减少 11 贡献,减少 dyidy_i 代价)可得更优的方案。

    • cic_i 等于 min(dxi,dyi)\min(dx_i, dy_i) 且不等于 max(dxi,dyi)\max(dx_i, dy_i)。不妨设 dxi<dyidx_i < dy_i。设 j=s(i,X)j = s(i, X),则要求 cjdxjc_j\geq dx_j。首先,因为 dxj=dxiw(i,j)dx_j = dx_i - w(i, j)dyjdyiw(i,j)dy_j \geq dy_i - w(i, j),所以 dxjdyjdx_j \leq dy_j。这说明只要 cjc_j 不为 00 就行。而 cjc_j 显然不会为 00,否则令 cjc_j 变成 dxjdx_j(增加 11 贡献,增加 dxjdx_j 代价),cic_i 变成 00(减少 11 贡献,减少 dxidx_i 代价)可得更优的方案。这说明在不考虑限制时用 Cardboard Box 的做法求出的解在该情况下的贡献是符合限制的。

    • cic_i 等于 max(dxi,dyi)\max(dx_i, dy_i)。不妨设 dxidyidx_i \leq dy_i。设 jx=s(i,X)j_x = s(i, X)jy=s(i,Y)j_y = s(i, Y)。这里又有两种情况:

      • jx=jyj_x = j_y,设为 jj,则 dxj=dxiw(i,j)dx_j = dx_i - w(i, j)dyj=dyiw(i,j)dy_j = dy_i - w(i, j),且要求 cj=dyjc_j = dy_j。此时 ii 恰好不在 X,YX, Y 的简单路径上。

        • 如果 cj=0c_j = 0,那么令 cjc_j 变成 dyjdy_j(增加 22 贡献,增加 dyjdy_j 代价),cic_i 变成 00(减少 22 贡献,减少 dyidy_i 代价)可得更优的方案。

        • 如果 cj=dxjc_j = dx_j,那么令 cjc_j 变成 dyjdy_j(增加 11 贡献,增加 dyjdxjdy_j - dx_j 代价),cic_i 变成 dxidx_i(减少 11 贡献,减少 dyidxidy_i - dx_i 代价)得到代价相等的方案。

        这说明在不考虑限制时用 Cardboard Box 的做法求出的解在该情况下的贡献要么符合限制,要么可以通过调整得到符合限制且代价不劣的方案。

      • 唯一的问题发生在 jxjyj_x\neq j_y,即 ii 落在 X,YX, Y 简单路径上且不等于 X,YX, Y 的时候。而且我们很容易举出一个这种情况下的反例:由 (1,2,2),(2,3,1),(3,4,1),(4,5,2)(1, 2, 2), (2, 3, 1), (3, 4, 1), (4, 5, 2) 组成的五元链,且 K=3K = 3。答案显然为 33,但我们会求出 c3=3c_3 = 3 使得总贡献为 44

    但是,如果至少一个点贡献了 22,那么 XXYY 之间所有点都要至少贡献 11。从这一点出发,考虑钦定 XXYY 之间所有点至少贡献 11。在此基础上做 Cardboard Box(这是容易的)是否就符合限制了呢?

    我们来具体分析一下:要求 cjxdxjxc_{j_x} \geq dx_{j_x}cjydyjyc_{j_y}\geq dy_{j_y}

    • 对于 cjxdxjxc_{j_x}\geq dx_{j_x}:因为 dxidyidx_i \leq dy_i,所以 dxjx<dyjxdx_{j_x} < dy_{j_x}。若 cjx>0c_{j_x} > 0,这个条件就一定满足。
    • 对于 cjydyjyc_{j_y}\geq dy_{j_y}
      • 如果 dyjydxjydy_{j_y}\leq dx_{j_y},那么若 cjy>0c_{j_y} > 0,这个条件就一定满足。
      • 如果 dyjy>dxjydy_{j_y} > dx_{j_y},那么若 cjy=dxjyc_{j_y} = dx_{j_y},可以令 cic_i 变成 dxidx_icjyc_{j_y} 变成 dyjydy_{j_y},贡献不变,但注意到 iijyj_y 在链上都是向 XX 偏的,所以代价会减少 2w(i,jy)2w(i, j_y)(把式子写出来可得同样的结果)。因此,若 cjy>0c_{j_y} > 0,这个条件就一定满足。

    也就是说,只要 cjx>0c_{j_x} > 0cjy>0c_{j_y} > 0,方案就一定合法。而这个先决条件恰好被 “钦定 XXYY 之间所有点至少贡献 11" 这一步操作满足了(特别地,对于 jx=Xj_x = Xjy=Yj_y = Y 的情况,因为此时 dxjx=0dx_{j_x} = 0dyjy=0dy_{j_y} = 0,所以合法),而该操作是必要条件,即所有合法方案都必须满足的条件,所以该操作不会丢掉合法方案。

    别忘了还有不存在一个城市从 X,YX, Y 均可达的情况,此时答案为最大的 kk 使得 {dxi}{dyi}\{dx_i\} \cup \{dy_i\}kk 小的元素之和不大于 KK。合法性已经证明过了,且如果方案有城市从 X,YX, Y 均可达,因为只会将代价算大,所以不影响答案的合法性。

    时间复杂度 O(NlogN)\mathcal{O}(N\log N)

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    using pii = pair<int, int>;
    
    constexpr int N = 4e5 + 5;
    
    ll z[N];
    struct level {
      ll a, b;
      bool operator < (const level &z) const {
        return b < z.b;
      }
    } c[N];
    
    namespace Cardboard_Box {
      int cnt, p[N], q[N];
      ll d[N], nu[N], su[N];
      void add(int x, int v1, ll v2) {
        while(x <= cnt) {
          nu[x] += v1, su[x] += v2;
          x += x & -x;
        }
      }
    
      int solve(int n, ll K, level *c, int m, ll *z) {
        cnt = 0;
        for(int i = 1; i <= m; i++) d[++cnt] = z[i];
        for(int i = 1; i <= n; i++) {
          d[++cnt] = c[i].a;
          d[++cnt] = c[i].b - c[i].a;
        }
        sort(c + 1, c + n + 1);
        sort(d + 1, d + cnt + 1);
        cnt = unique(d + 1, d + cnt + 1) - d - 1;
        
        ll sum = 0;
        memset(nu, 0, cnt + 2 << 3);
        memset(su, 0, cnt + 2 << 3);
        for(int i = 1; i <= m; i++) {
          int pos = lower_bound(d + 1, d + cnt + 1, z[i]) - d;
          add(pos, 1, z[i]);
        }
        for(int i = 1; i <= n; i++) {
          p[i] = lower_bound(d + 1, d + cnt + 1, c[i].a) - d;
          q[i] = lower_bound(d + 1, d + cnt + 1, c[i].b - c[i].a) - d;
          add(p[i], 1, c[i].a);
        }
    
        ll ans = 0;
        for(int i = 0; i <= n; i++) {
          if(i) {
            add(p[i], -1, -c[i].a);
            add(q[i], 1, c[i].b - c[i].a);
            K -= c[i].a;
          }
          if(K < 0) break;
          ll p = 0, num = 0, sum = 0;
          for(int j = __lg(cnt); ~j; j--) {
            int np = p + (1 << j);
            if(np > cnt || sum + su[np] > K) continue;
            p = np, num += nu[p], sum += su[p];
          }
          if(p < cnt) num += (K - sum) / d[p + 1];
          ans = max(ans, num + i);
        }
        return ans;
      }
    }
    
    ll dx[N], dy[N];
    vector<pii> e[N];
    void dfs(int id, int ff, ll *d) {
      if(ff == -1) d[id] = 0;
      for(pii _ : e[id]) {
        int it = _.first;
        if(it == ff) continue;
        d[it] = d[id] + _.second;
        dfs(it, id, d);
      }
    }
    
    int max_score(int N, int X, int Y, ll K, vector<int> U, vector<int> V, vector<int> W) {
      for(int i = 0; i < N; i++) e[i].clear();
      for(int i = 0; i + 1 < N; i++) {
        e[U[i]].push_back({V[i], W[i]});
        e[V[i]].push_back({U[i], W[i]});
      }
      dfs(X, -1, dx), dfs(Y, -1, dy);
    
      vector<ll> arr;
      for(int i = 0; i < N; i++) {
        arr.push_back(dx[i]);
        arr.push_back(dy[i]);
      }
      sort(arr.begin(), arr.end());
    
      int ans = 0;
      ll sum = 0;
      for(int i = 0; i < arr.size(); i++) {
        if((sum += arr[i]) > K) break;
        ans++;
      }
    
      int n = 0, m = 0, cnt = 0;
      for(int i = 0; i < N; i++) {
        ll mn = min(dx[i], dy[i]);
        ll mx = max(dx[i], dy[i]);
        if(dx[i] + dy[i] == dx[Y]) {
          cnt++, K -= mn;
          z[++m] = mx - mn;
        }
        else c[++n] = {mn, mx};
      }
    
      if(K >= 0) ans = max(ans, cnt + Cardboard_Box::solve(n, K, c, m, z));
      return ans;
    }
    
    • 1

    信息

    ID
    9178
    时间
    1000ms
    内存
    2048MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者