寒假第二次考试t1
题意简述
这是一道签到题吗
给定一个长度为n的整数序列 \(a\),每次可以选择一个位置 \(i\),花费( \(a_i−_1 ⊕ a_i ⊕ a_i+_ 1\) )的代价删去第 \(i\) 个数。
删去该数后,该数后面的所有数将均往前推一位。
求删完所有数所需的最大代价。(注:\(a ⊕ b\) 表示二进制异或)
思路分析
这是一道区间dp吗
取定一组 \(l\)、\(r\)。假设第 \(l\) 到第 \(r\) 个数之间,最后被删除的数是第 \(k\) 个;
那么删除第 \(k\) 个数的代价一定是 \(a_l-_ 1\) ⊕ \(a_k\) ⊕ \(a_r+_ 1\)。
设 \(dp\):\(dp_l,_ r\) 为删除第 \(l\) 到第 \(r\) 的所有数的代价之和。
则可得递推式:\(dp_l,_ r\) = \(max\)( \(dp_l,_ k-_1\), $dp_ k+_ 1,_ r $ + \(dp_k,_ k\))。
但具体按照什么顺序去推呢。
我们可以枚举区间长度;然后在此之下枚举左端点,并通过左端点求出右端点。
随后再按照递推式求解。
记得把所有 \(dp_i, _ i\) 初始化为( \(a_i−_1 ⊕ a_i ⊕ a_i+_ 1\) )。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 510;
int n, a[N], dp[N][N];
signed main(){
scanf("%lld", &n);
for(int i = 1; i <= n; i++){
scanf("%lld", &a[i]);
}
for(int i = 1; i <= n; i++){
dp[i][i] = a[i - 1] ^ a[i] ^ a[i + 1];
}
for(int len = 2; len <= n; len++){
for(int l = 1; l + len - 1 <= n; l++){
int r = l + len - 1;
for(int k = l; k <= r; k++){
int jl = a[l - 1] ^ a[k] ^ a[r + 1];
dp[l][r] = max(dp[l][r], dp[l][k - 1] + dp[k + 1][r] + jl);
}
}
}
printf("%lld", dp[1][n]);
return 0;
}
浙公网安备 33010602011771号