lg7335 [JRKSJ R1] 异或 题解

本题的标签中含有trie,但是这道题可以不用trie做。
考虑列出本题的dp方程:设fk,i表示前i个数选了k段的答案,si为数组的前缀异或和
当不选择第i位,使用fk,i1更新fk,i。当选择第i位时,枚举选择的区间的左端点j+1,使用fk1,j+sj xor sk更新fk,i
由于本题数据随机,考虑更为优秀的做法。枚举k,i,设aj=sj xor si,则a可以看做随机数列。
显然fk,1...n单调递增,所以假设存在2个位置j<kaj<ak,那么不用考虑j
利用该性质,设gk表示k左边的第一个大于ak的点(不存在视为0),则对于fk,i,可行的决策点为i,gi,ggi...,即不断地执行i=gi操作直到i=0所经过的非0点所构成的集合。
根据经典结论,这个集合的期望大小为log2n,所以此做法时间复杂度为O(n2log2n)

#include<bits/stdc++.h>
using namespace std;
#define N 3010
int g[N][N],n,k,a[N],s[N],tp[N],ans;
long long f[N][N];
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		s[i]=s[i-1]^a[i];
		tp[i]=1;
		g[i][1]=i-1;
		for(int j=i-2;~j;j--){
			if((s[i]^s[j])>(s[i]^s[g[i][tp[i]]]))
				g[i][++tp[i]]=j;
		}
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			f[k][i]=max(f[k][i],f[k][i-1]);
			for(int j=1;j<=tp[i];j++)
				f[k][i]=max(f[k][i],f[k-1][g[i][j]]+(s[g[i][j]]^s[i]));
		}
	}
	printf("%lld",f[k][n]);
}
posted @   celerity1  阅读(20)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示