(CodeForce) F. Ivan and Burgers(线性基+离线)

视频题解戳这里

传送门

题目大意:有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;
}

猜你喜欢

转载自blog.csdn.net/TDD_Master/article/details/86489939