视频题解戳这里
题目大意:有n个汉堡店,每个店里最贵的汉堡是ci元,q次询问,从l到r,所能花费的最多钱数(结束与开始时的金额差),但是花钱不是直接的加减,规则是手里有d元,要花费c元,那支付只后,他还有d^c元。开始是他有非常多个1(rich)。
解题思路:其实这个题稍微思考一下就可以转化成求(l,r)区间的最大异或值,这个值和他初始的钱异或,差值就是这个数。然后又要多次查询,时间复杂度如何降下来呢,就需要用到线性基的知识了(不懂戳我)主要是用到了一个关键的性质,a和b异或的值域和将a,b之一替换成a^b(a异或b)的值域是一样的。
接下离线操作,从小到大依此处理第i个汉堡店,解决右边界为i的查询。所以用线性基的时候就要多加一句
else if(f[j].b<tmp.b){ //b的值是出现的位置i
swap(f[j],tmp);
}
这是 使得二进制第j位为1的数 出现的位置最大
if(f[j].b>=tp.a){
ans[tp.b]=max(ans[tp.b],ans[tp.b]^f[j].a);
}
这样在判断区间时,只要查询的左边界l是 小于 使得第j位为1的数的位置(好绕口)那就说明这个数可以被考虑,就try一下。
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int maxn=5e5+5;
const int tt=20;
struct node{
int a;
int b;
};
int n,c[maxn],ans[maxn],q,l,r;
node f[tt];
vector<node> que[maxn];
int main(){
std::ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;++i){
cin>>c[i];
}
cin>>q;
for(int i=1;i<=q;++i){
cin>>l>>r;
que[r].push_back(node{l,i}); //记录左边界和第几组询问
}
//f[i].a表示可以使得i位变成1的数,f[i].b表示满足条件的坐标最大的点
for(int i=1;i<=n;++i){
node tmp=node{c[i],i};
for(int j=tt-1;j>=0;--j){ //每一个的每一位取出 ,从高位到低位
if(tmp.a>>j&1){
if(f[j].a==0){
f[j]=tmp;
break;
}
else if(f[j].b<tmp.b){ //该位置已经为有数,并且这个数也可以使得为 1
swap(f[j],tmp);
}
tmp.a^=f[j].a;
}
}
for(int k=0;k<(int)que[i].size();++k){ //处理掉以i为右边界的查询
node tp=que[i][k];
for(int j=tt-1;j>=0;j--){
if(f[j].b>=tp.a){
ans[tp.b]=max(ans[tp.b],ans[tp.b]^f[j].a);
}
}
}
}
for(int i=1;i<=q;++i){
cout<<ans[i]<<endl;
}
return 0;
}