Codeforces Round #830 (Div. 2) 题解

AB 太简单了,不写解法了。

CF1732C Sheikh

我们观察一下 f(l,r)=sum(l,r)xor(l,r) 的性质。

考虑假如一个数 x,对 sum 的贡献为 x,而对 xor 的贡献小于等于 x,因为可能异或和中已经有位为 1

所以固定 lf(l,r) 单调递增,固定 r 也有此性质。

另一个显而易见的结论是假如不要求区间长度最小,[L,R] 就是最终的答案,所以其实最大值已经确定为 f(L,R),只需要找长度最小的区间满足 f(l,r)=f(L,R) 即可。

由此结论,我们可以完成 C1,对于 i[L,R],先判断如果 jR 也就是最大能不能达到 f(L,R),若能二分出使 f(i,j) 最大的 jmin,最后求出最小长度即可。

复杂度 O(Tnqlogn),其中 q=1.


接下来考虑 C2,qn 同阶,所以我们一次询问要求做到 O(logn) 以内。

不知道有多少人可能想到过一个错误的做法:初始区间为 [L,R],若左右端点能缩就缩。

我们规定 l1=Ll1R 作为右端点时区间满足 f=f(L,R) 左端点的最大值。

它错的原因是没有考虑每一个 l[l1,l2] 所对应的最小 r,而是直接考虑了最大的 l=l2 对应的最小 r,从而遗漏了一些情况。

那么假如我们枚举每一个 l[l1,l2],然后二分的话,复杂度如何呢?

显然如果区间中 0 很多,一次询问就会被卡到 O(nlogn),这是我们不能接受的。

如果排除 0 的干扰,考虑答案区间 [l,r],它满足加入 al1ar+1 后值不变(前提时 L<lr<R),说明 al1ar+1 的二进制位在 xor(l,r) 中都为 0,那么最多有多少个这样的数呢,我们考虑每一个未加入的数都是 2k,约有 logV 个。所以 l2l1+1 是小于 logV 的,复杂度就有了保证。

加上 0 的干扰,我们只需要预处理出每一个数前面和后面第一个非 0 数,然后枚举 l[l1,l2] 改成 lL 及之后第一个非 0 数开始往后跳 l2l1+1 次即可。

复杂度 O(TqlogVlogn),但显然跑不满。

代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long

inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c<='9'&&c>='0'){
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}
	return x*f;
}

void print(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)print(x/10);
	putchar(x%10^48);
}

const int N=1e5+5;
int T,n,q,a[N],sum[N],xsum[N];

int erfen1(int ll,int rr,int fmax){
	int l=ll,r=rr,mid;
	while(l<r){
		mid=l+r>>1;
		if(sum[mid]-sum[ll-1]-(xsum[mid]^xsum[ll-1])>=fmax)r=mid;
		else l=mid+1;
	}
	return l;
} 

int erfen2(int ll,int rr,int fmax){
	int l=ll,r=rr,mid;
	while(l<r){
		mid=l+r+1>>1;
		if(sum[rr]-sum[mid-1]-(xsum[rr]^xsum[mid-1])>=fmax)l=mid;
		else r=mid-1;
	}
	return l;
}

int nxt[N],pre[N];

signed main(){
	T=read();
	while(T--){
		n=read(),q=read();
		for(int i=1;i<=n;++i){
			a[i]=read();
			sum[i]=sum[i-1]+a[i];
			xsum[i]=(xsum[i-1]^a[i]);
		}
		int lst=0;
		for(int i=1;i<=n;++i){
			pre[i]=lst;
			if(!a[i])continue;
			lst=i;
		}
		lst=n+1;
		for(int i=n;i>=1;--i){
			nxt[i]=lst;
			if(!a[i])continue;
			lst=i;
		}
		while(q--){
			int L=read(),R=read();
			if(sum[R]==sum[L-1]){print(L),printf(" "),print(L),puts("");continue;}
			if(!a[L])L=nxt[L];
			if(!a[R])R=pre[R];
			int fmax=sum[R]-sum[L-1]-(xsum[R]^xsum[L-1]);
			int cnt=erfen2(L,R,fmax)-L+1,l=L,r=R,i=L;
			while(cnt--){
				if(sum[R]-sum[i-1]-(xsum[R]^xsum[i-1])<fmax)break;
				int j=erfen1(i,R,fmax);
				if(j-i<r-l)l=i,r=j;
				i=nxt[i];
				if(i>n)break;
			}
			print(l),printf(" "),print(r),puts("");
		}
	}
	return 0;
}

CF1732D

暴力与优化结合,从而获得较优的复杂度。

代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long

inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c<='9'&&c>='0'){
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar();
	}
	return x*f;
}

void print(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)print(x/10);
	putchar(x%10^48);
}

int q;
set<int>s1,s2;
map<int,int>f; 

signed main(){
	q=read();
	s1.insert(0);
	while(q--){
		char opt;
		cin>>opt;
		int x=read();
		if(opt=='+'){
			s1.insert(x),f[x]=x+x;
			if(s2.count(x))s2.erase(x);
		}else if(opt=='-'){
			s2.insert(x);
			if(s1.count(x))s1.erase(x);
		}else{
			int tmp;
			if(f[x])tmp=f[x];
			else tmp=x;
			while(s1.count(tmp))tmp+=x;
			f[x]=tmp;
			for(auto i=s2.lower_bound(x);i!=s2.end();++i){
				if((*i)>tmp)break;
				if((*i)%x==0){
					tmp=(*i);break;
				}
			}
			print(tmp),puts("");
		}
	}
	return 0;
}

E 赛时都没做到,不想花时间补了。

posted @   Daidly  阅读(181)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示