codeforces1511G. Chips on a Board

这篇博客介绍了如何运用倍增技巧来高效求解数组中一段连续子区间内所有元素距离起始位置的异或和。通过预处理f[k][i]表示从i开始的2^k长度区间内的异或和,博主详细阐述了如何利用位运算优化计算过程,并给出了完整的C++代码实现。这种方法相较于传统分块策略,有着更高的效率。

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

https://codeforces.com/contest/1511/problem/G

雅米老师教了我一手倍增做这题,奥妙重重,比题解分块高到不知道哪里去了

设f[k][i]表示从i列开始向后的连续2^k的块中所有点到i的距离的异或和

f[k][i]=f[k-1][i]^f[k-1][i+2^(k-1)],但是我们发现i+2^(k-1)到i+2^k-1这一段的所有点其实都长度增加了2^(k-1),且由于f[k-1]中所有连续块的长度最多是2^(k-1),所以他们到左边界的值最大是2^(k-1)-1的,所以增加2^(k-1)对于本身异或和是独立的

所以如果i+2^(k-1)到i+2^k-1这一段中有奇数个点的话,f[k][i]^=1<<(k-1)

最后求答案的时候也是,从l开始倍增,每次l+=1<<k,然而从当前l到实际的r中所有点到实际 l的距离都多增加了2^k,所以后面如果还有奇数个点的话,就要res^=2^k

 

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

const int maxl=2e5+10;

int n,m,q;
int c[maxl],sum[maxl];
int f[21][maxl];

inline void prework()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&c[i]);
		sum[c[i]]^=1;
	}
	for(int i=1;i<=m;i++)
		sum[i]^=sum[i-1];
	for(int k=1;k<=20;k++)
		for(int i=1;i+(1<<k)-1<=m;i++)
		{
			int r=i+(1<<k)-1;
			f[k][i]=f[k-1][i]^f[k-1][i+(1<<(k-1))];
			if(sum[r]^sum[i+(1<<(k-1))-1])
				f[k][i]^=1<<(k-1);
		}
}

inline void mainwork()
{
	scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		int l,r,res=0;scanf("%d%d",&l,&r);
		for(int k=20;k>=0;k--)
		if(l+(1<<k)-1<=r)
		{ 
			res^=f[k][l],l+=(1<<k);
			if(sum[r]^sum[l-1])
				res^=1<<k; 
		} 
		putchar(res?'A':'B');
	}
}

int main()
{
	prework();
	mainwork();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值