dp优化(1) - 预处理

HDU 25春季联赛 - 0 - 1007

题意:

给定长度 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];
}

// f(pre[j], pre[i]) , max( dp[j]-j*(pre[j]*pre[i]) )
vector<vector<ll>> f(1024, vector<ll>(1024, -inf)); // 记得初始化, ( dp[j]-j*(pre[j]*pre[i]) ) 可能为负
ll ans = 0;
for(int i=0; i<=n; i++){ // pre[0] 也要处理
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++){ // 对于 pre[i] 预处理出所有 f[pre[i]][0...1023]
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; //cin >> t;
while(t--) solve();

return 0;
}