字符串训练之二

字符串训练****

例题二:

https://loj.ac/problem/10051

题目描述:

在一个有 N个元素的序列 A 中,找出 下面式子的最大值

(A[L1]A[L1+1]^^^^A[R1-1]A[R1])+(A[L2]A[L2+1]^^^^A[R2-1]A[R2])的最大值

且要满足:1<=L1<=R1<L2<=R2<=N,N<=4e5,Ai<=1e9;

分析:肯定看到这题目描述想什么狗屁字符串,应该乱搞可以过の

但当你仔细想想乱搞是搞不出来的.....emmm

首先肯定能够想到和前缀异或有关

又是一个最值问题????dp

然后发现式子中间是有断点的

假如知道了断点前的最大值****和断点后的最大值**

加起来O(n)线性扫一遍不就知道答案了吗?

pre[i]+suf[i+1];

现在主要就是求pre[i],suf[i]同理

现在就要利用前面说的前缀异或

设sum[i]=A[1]A[2]A[3]^^^^^^A[i];

pre[x]=max(sum[i]^sum[j])其中1<=i<=j<x

问题转化为

要求一个序列中[1,x]任意两个异或的最大值[板子题]

solution:

二进制拆分,放入一个Trie中,从最高位开始,每次选与它相反的(0--->1||1--->0),如果没得选就直接向下走

同理suf

code:

#include <iostream>
using namespace std;
int n,a[5000000],now,trie[50000000][3],tot,l[5000000],r[5000000],ans;
int insert(int x)
{
	int u(0);
	for (int i=30;i>=0;i--)
	{
		int ch=(x>>i)&1;
		if (!trie[u][ch])trie[u][ch]=++tot;
		u=trie[u][ch];
	}
}
int query(int x)
{
	int u(0),an(0);
	for (int i=30;i>=0;i--)
	{
		int ch=(x>>i)&1;
		if (trie[u][!ch])u=trie[u][!ch],an+=1<<i;
		else u=trie[u][ch];
	}
	return an;
}
int clear()
{
	for (int i=0;i<=tot;i++)
		for (int j=0;j<=1;j++)
			trie[i][j]=0;
	tot=0;
	now=0;
}
int main()
{
	cin>>n;
	insert(0);
	for (int i=1;i<=n;i++)
		cin>>a[i],now^=a[i],insert(now),l[i]=max(l[i-1],query(now));
	clear();
	insert(0);
	for (int i=n;i>=1;i--)
		now^=a[i],insert(now),r[i]=max(r[i+1],query(now));
	for (int i=1;i<n;i++)
		ans=max(ans,l[i]+r[i+1]);
	cout<<ans<<endl;
	return 0;
} 
原文地址:https://www.cnblogs.com/wzxbeliever/p/11610269.html