HZAU 1206:01字典树求 抑或最大和

本文介绍了一种解决区间抑或和最大值问题的方法,通过枚举区间右端点并利用01字典树来查找使抑或和最大的左端点,确保找到的区间字典序最小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出n个数字(n<=1e6),求出一段区间[ l , r ]使得这段区间数字的抑或和最大。如果有多个最大区间,输出字典序最小的一个。

题解:枚举区间右端点 r ,那么左端点 l 一定比 r 小,同时[ l , r ]的抑或和可以表示成 [ 1, r ]xor[ 1 , l-1 ],那么我们枚举一个 r,求出[ 1, r]的和,然后就是查询[1, 1 ][ 1, 2 ] [1 , 3 ]……[1, r-1]中和[1,r]抑或最大的那个值。这个可以通过01字典树完成,然后还要求字典序最小,字典树终点处记一个l位置,然后更新就行了。


PS:数组模拟字典树

Code:

#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX = 1e6+100;
int bas[35];
const int INF = 2147483645;
struct Trie{
	int nxt[MAX<<2][2];
	int l[MAX<<2];
	int cnt;
	int ansl,ansr,ansv;
	void init(){
		cnt =0;
		memset(nxt[0],0,sizeof (nxt[0]));
		memset(l,0x3f3f3f3f,sizeof(l));
		ansv = 0;
	}
	int create(){
		cnt++;
		memset(nxt[cnt],0,sizeof (nxt[cnt]));
		return cnt;
	}
	void insert(int id,int x){
		int y = 0;
		for (int i=30;i>=0;i--){
			int t = x&bas[i];
			t>>=i;
			if (!nxt[y][t]){
				nxt[y][t] = create();
			}
			y = nxt[y][t];
		}
		l[y] = min(l[y],id);
	}
	void query(int id,int x){
		int y=0;
		int res =0;
		for (int i=30;i>=0;i--){
			int t = x&bas[i];
			t>>=i;
//			cout<<t<<" "<<nxt[y][!t]<<endl;
			if (nxt[y][!t]){
				y =nxt[y][!t];
				res+=bas[i]; 
			}else{
				y = nxt[y][t];
			}
		}
//		cout<<"Query: "<<l[y]<<" "<<id<<" "<<x<<" "<<res<<" "<<ansv<<endl;
		if (res==ansv){
			if (l[y]<ansl){
				ansl = l[y];
				ansr = id;
			}
		}else if (res>ansv){
			ansv = res;
			ansl = l[y];
			ansr = id;
		}
	}
	void print(int id){
		printf("Case #%d:\n%d %d\n",id,ansl+1,ansr);
	}
}trie;
void init(){
	bas[0] = 1;
	for (int i=1;i<=30;i++){
		bas[i] = bas[i-1]<<1;
	}
}
int main(){
	init();
	int n,Cas;
	scanf("%d",&Cas);
	for (int i=1;i<=Cas;i++){
		trie.init();
		trie.insert(0,0);
		scanf("%d",&n);
		int sum=0;
		for (int j=1;j<=n;j++){
			int ai;
			scanf("%d",&ai);
			sum^=ai;
			trie.query(j,sum);
			trie.insert(j,sum);
		}
		trie.print(i);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值