#3579. 晚安。

statement


考虑题意即给定每一位 \(i\in[0,m)\) 的权值函数 \(w_i(x,y)\)

对于 \(w(x,y)=\displaystyle\sum_{i=0}^{m-1}w_i(x_i,y_i)\),求 \(\displaystyle\max_{x,y\in S} w(x,y)\)


对于这种位贡献独立的题,有一个 trick 是高低位分治。

考虑将 \(w(x,y)\) 拆为高 \(m/2\) 位的贡献 \(H\) 和低 \(m/2\) 位的贡献 \(L\)

不妨枚举 \(x\)\(y\) 的高 \(m/2\)\(y_H\),则我们可以计算 \(w_H\),将其中最大值记作 \(W_H(x_L,y_H)\)。同理维护 \(W_L(x_H,y_L)\)

当我们计算答案时,我们枚举 \(x_L,y_H\),用 \(W_H(x_L,y_H)+W_L(y_H,x_L)\) 更新答案。

那么时间复杂度 \(\mathcal O(N\sqrt V)\)


我们发现计算 \(H,L\)\(\mathcal O(V^\frac32)\) 的,但统计答案是 \(\mathcal O(V)\) 的。

考虑平衡。具体地,我们将一个数分为 \(x_0,x_1,x_2\) 分别表示低中高三段。

那么我们枚举 \(x_0,x_1,x_2,y_2\),则可以计算 \(w_2\) 最大值,记作 \(W_2(x_0,x_1,y_2)\)。同理维护 \(W_1(x_0,y_1,x_2)\)

统计答案时考虑枚举 \(x_0,y_0,x_1,y_2\),用 \(w(x_0,y_0)+W_1(y_0,x_1,y_2)+W_2(x_0,x_1,x_2)\) 更新答案。

即可平衡到 \(\mathcal O(N\sqrt[3]{V})\)


能不能再给力一点?

我们考虑计算 \(w(x,y)\) 抽象成这么一个操作:

依次对于每一位,将 \(x_i\) 替换为 \(y_i\),并将贡献加上 \(w_i(x_i,y_i)\)

不难发现初始状态为 \(x\),结束状态为 \(y\),且这个过程可以快速维护。

时间复杂度 \(\mathcal O(V\log V)\)


但上面的方法是离线的。在线还是需要使用高低位分治。

对于本题,时间复杂度 \(\mathcal O(V\log V+N\sqrt V)\)

#include <algorithm>
#include <iostream>
#include <vector>
#include <bitset>
#include <array>

auto updt = [](auto& x, auto&& y) { if(y > x) { x = y; return 1; } return 0;};
auto upd = [](auto& x, auto&& y) { x = std::max(x, y); };
inline void solve() {
  typedef long long i64;

  int n, m, q;
  std::cin >> n >> m >> q;

  std::vector<std::array<i64, 3>> w(m);
  std::vector<i64> A(m), C(m);
  [&](){
    std::vector<i64> x(m), y(m), z(m);
    for(int i = 0; i < m; ++i) std::cin >> y[i];
    for(int i = 0; i < m; ++i) std::cin >> x[i];
    for(int i = 0; i < m; ++i) std::cin >> z[i];
    for(int i = 0; i < m; ++i) {
      w[i][0] = 0;
      w[i][1] = z[i] + y[i];
      w[i][2] = x[i] + y[i];

      C[i] = z[i] + y[i];
      A[i] = x[i] - z[i];
    }
  }();

  int dm = m / 2;
  std::vector<i64> buck(1<<m);
  for(int i = 1; i <= n; ++i) { int a; std::cin >> a; buck[a] = 1; }

  std::basic_string<i64> F(1<<m, -1e18), G(1<<m, -1e18);
  for(int i = 0; i < 1 << m; ++i) if(buck[i]) F[i] = G[i] = 0;
  for(int i = 0; i < dm; ++i) {
    int t = 1 << i;
    for(int j = 0; j < 1 << m; j += t << 1) {
      for(int k = 0; k < 1 << i; ++k) {
        i64 x = F[j|k], y = F[j|t|k];
        F[j|k] = std::max(x + w[i][0], y + w[i][1]);
        F[j|t|k] = std::max(x + w[i][1], y + w[i][2]);
      }
    }
  }
  for(int i = dm; i < m; ++i) {
    int t = 1 << i;
    for(int j = 0; j < 1 << m; j += t << 1) {
      for(int k = 0; k < 1 << i; ++k) {
        i64 x = G[j|k], y = G[j|t|k];
        G[j|k] = std::max(x + w[i][0], y + w[i][1]);
        G[j|t|k] = std::max(x + w[i][1], y + w[i][2]);
      }
    }
  }

  i64 ans = -1e18;
  for(int i = 0; i < 1 << m; ++i) upd(ans, G[i] + F[i]);
  std::cout << ans << " ";

  std::vector<i64> vC(1<<dm), vA(1<<dm);
  for(int j = 0; j < dm; ++j) for(int i = 0; i < 1 << j; ++i)
      vC[i | 1 << j] = vC[i] + C[j], vA[i | 1 << j] = vA[i] + A[j];
  std::vector<i64> wC(1<<dm), wA(1<<dm);
  for(int j = 0; j < dm; ++j) for(int i = 0; i < 1 << j; ++i)
      wC[i | 1 << j] = wC[i] + C[j+dm], wA[i | 1 << j] = wA[i] + A[j+dm];

  for(; q--; ) {
    int a; std::cin >> a;
    if(!buck[a]) {
      buck[a] = 1;
      int x = a & ((1 << dm) - 1), y = a >> dm;
      for(int k = 0; k < 1<<dm; ++k) {
        int t1 = x|k<<dm, t2 = k|y<<dm;
        if(updt(G[t1], wC[y|k] + wA[y&k]))
          upd(ans, G[t1] + F[t1]);
        if(updt(F[t2], vC[x|k] + vA[x&k]))
          upd(ans, G[t2] + F[t2]);
      }
    }
    std::cout << ans << " ";
  }

  std::cout << "\n";
}

int main() {
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int c, t; std::cin >> c >> t; while(t--) solve();
}
posted @ 2026-07-25 14:10  CuteNess  阅读(11)  评论(0)    收藏  举报