#3579. 晚安。
考虑题意即给定每一位 \(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();
}
本文来自博客园,作者:CuteNess,转载请注明原文链接:https://www.cnblogs.com/CuteNess/p/21909641

浙公网安备 33010602011771号