XCPCXCPCdpdp优化(1) - 预处理
amiracle
题意:
给定长度 n 的数组 a,
定义 [l, r] 价值为
⨁i = lrai ⋅ (r − l + 1),
定义 f(a) 为数组
a 划分后的最大价值和,
求
(n ≤ 2e5, 0 ≤ ai < 1024)
解析:
很容易想到 n2
dp
pre
为前缀异或数组
定义 dpi
→ 用前 i 个元素能得到的最大价值
转移方程:
复杂度不可接受, 尝试优化
我们拆开式子:
1.先考虑一个更简单的式子: 观察左侧部分: dpj − (prei ⊕ prej) ⋅ j
当我们在 j 时, 未知量只有
prei
定义 g(x) → max{dpj − (x ⊕ prej) ⋅ j}
我们遍历到 j 时, 对所有可能的
x 的值进行预处理
转移方程:
由 ai < 1024
可知 x < 1024
预处理时间复杂度 O(1024)
转移复杂度 O(1)
总时间复杂度 O(1024 ⋅ n)
2.让我们回到原式 类似地
定义 g(x, y) → max{dpj − (x ⊕ y) ⋅ j}
进行同样的预处理操作即可
因为 prej
未知, 我们还需要枚举一下
转移方程: 预处理操作 O(1024)
转移 O(1024)
总时间复杂度 O(1024 ⋅ n)
MYCODE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include <bits/stdc++.h> using namespace std; using ll = long long;
const ll inf = 1e18;
void solve(){ int n; cin >> n; vector<int> a(n + 1), pre = a; vector<ll> dp(n + 1, -inf); dp[0] = 0;
for(int i=1; i<=n; i++){ cin >> a[i]; pre[i] = pre[i-1] ^ a[i]; } vector<vector<ll>> f(1024, vector<ll>(1024, -inf)); ll ans = 0; for(int i=0; i<=n; i++){ for(int j=0; j<1024; j++){ dp[i] = max(dp[i], 1ll * f[j][pre[i]] + i*(j^pre[i])); } for(int k=0; k<1024; k++){ f[pre[i]][k] = max(f[pre[i]][k], dp[i]-i*(pre[i]^k)); } ans += dp[i]; } cout << ans << '\n'; }
int main(){ ios::sync_with_stdio(false); cin.tie(nullptr);
int t = 1; while(t--) solve(); return 0; }
|