牛客练习赛81 B. 小 Q 与彼岸花(DP/Trie/树状数组/FWT/好题)

链接:https://ac.nowcoder.com/acm/contest/11171/B
来源:牛客网

小 Q 的院子里种了 n朵彼岸花,其中第 i 朵的彼岸花的美丽值为 ai,彼岸花按照编号从小到大从左向右排成了一排。

现在小 Q 有 m 个问题,他每次会给出一个区间 [l,r][l,r],他想在编号属于区间 [l,r][l,r] 的彼岸花中选出两朵花,使得 ai⨁aj(⨁ 表示按位异或操作) 的值最大(如果只能选出一朵花请直接输出 0)。

由于他太菜了,只能来问你了。

输入描述:

第一行两个整数 n,m(1≤n,m≤5×103)。            
第二行 n 个整数,分别表示 a1,a2,...,an(1≤ai≤210)。       
接下来 m 行,每行两个整数分别表示一个问题所给出的区间 l,r(1≤l≤r≤n)。

输出描述:

输出 m 行,表示每个问题的答案。

示例1

输入

复制

10 10
1 2 3 4 5 6 7 8 9 10
1 2
1 3
1 5
2 6
2 8
2 10
3 7
8 10
6 9
1 7

输出

复制

3
3
7
7
15
15
7
3
15
7

这个题有n多种做法,包括但不限于DP,01Trie(https://ac.nowcoder.com/acm/contest/view-submission?submissionId=47558628),树状数组(https://ac.nowcoder.com/acm/contest/view-submission?submissionId=47559728),FWT(https://ac.nowcoder.com/acm/contest/view-submission?submissionId=47557524)以及看不懂的做法。

最简单的还是DP,可以解决静态查找区间最值的问题。设dp[i, j]表示i到j区间任取两个数能够异或出来的最大值,初始化dp[i, j] = a[i] ^ a[j],有转移方程:(dp[i, j] = max(dp[i, j], dp[i + 1, j], dp[i, j - 1]))。即i到j的能够异或出来的最大值可能从i到j - 1,i + 1到j以及a[i]^a[j]中取得。注意遍历的顺序。

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m;
long long a[5005], dp[5005][5005];
#define ll long long
signed main() {
	cin >> n >> m;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= n; i++) {
		dp[i][i] = a[i];
		for(int j = 1; j <= n; j++) {
			dp[i][j] = a[i] ^ a[j];
		}
	}
	for(int i = n; i >= 1; i--) {
		for(int j = i + 1; j <= n; j++) {
			dp[i][j] = max(dp[i][j], max(dp[i][j - 1], dp[i + 1][j]));
		}
	}
	for(int i = 1; i <= m; i++) {
		int l, r;
		cin >> l >> r;
		if(l == r) cout << 0 << endl;
		else {
			cout << dp[l][r] << endl;
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/lipoicyclic/p/14696026.html