寒假第二次考试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;
} 
posted on 2026-02-03 21:34  Chronomia  阅读(0)  评论(0)    收藏  举报