我是靠谱客的博主 孝顺小熊猫,最近开发中收集的这篇文章主要介绍CodeForces - 1323D Present(思维+数学),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题目链接:点击查看

题目大意:给出一个数列 a ,求出

 (a_1 + a_2) oplus (a_1 + a_3) oplus ldots oplus (a_1 + a_n) \ oplus (a_2 + a_3) oplus ldots oplus (a_2 + a_n) \ ldots \ oplus (a_{n-1} + a_n) \

题目分析:如果暴力的话显然时间复杂度是 n * n 的,我们应该想办法去优化,比赛的时候想用线段树,但是不会在维护异或的前提下区间加法,也想过用矩阵维护,但丝毫没什么用呀,队友想到了可以按位维护,也就是维护26个线段树,我觉得太麻烦了就放弃这个题了,补题的时候看了题解,感觉题解已经说的很明白了,在这里再记录一下吧,感觉还是自己太菜了,需要多做题长见识

题解的意思是,可以按位维护,因为异或等位运算,最大的特点就是,每一位都可以视为独立的个体,互不影响,互不干预,这样我们在单独处理第 k 位的时候,因为要计算 a[ i ] + a[ j ] 后再进行异或,所以显然某个数大于 2^{k+1} 的部分是没有贡献的,我们可以先让每个数对 2^{k+1} 取模,因为后面我们需要二分查找,所以取模后对于整个数组排一下序,到此为止,所有的 a 数组中的每个元素的取值范围都是 [ 0 , 2^{k+1}-1] ,显然 a[ i ] + a[ j ] 的取值范围是 [0,2^{k+2}-2] ,不难看出第 k 位为 1 时的 a[ i ] + a[ j ] 的取值范围为 [2^k,2^{k+1}-1]cup [2^{k+1}+2^k,2^{k+2}-2] ,这样我们就可以固定下来 i ,从而二分查找符合条件的 j ,记录下来有多少对 ( i , j ) 可以对第 k 位做出贡献,因为 a[ i ] + a[ j ] 的范围上面已经确定下来了,那么当 a[ i ] 确定时,a[ j ]的范围也就非常容易确定了:[2^k-a[i],2^{k+1}-1-a[i]]cup [2^{k+1}+2^k-a[i],2^{k+2}-2-a[i]] 。如果 k 是奇数的话,那么答案的第 k 位就是 1 ,否则答案的第 k 位就是 0

上面是思路,具体实现的话可以用upper_bound和lower_bound搭配使用,并且注意二分的范围,如果每次都从[1,n]的范围二分,会导致答案重复,所以我们可以将范围控制为[1,i]就好了,i 为枚举的位置

然后因为上面的取模操作,我懒得再开一个新数组储存答案了,于是就在原数组上修改,不过这样的话就需要从最高位开始计算答案了,时间复杂度为 n * logn * logC ,C为1e7,也就是 a[ i ] 的最大值

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;
      
typedef long long LL;
     
typedef unsigned long long ull;
      
const int inf=0x3f3f3f3f;
 
const int N=4e5+100;

int a[N];

int main()
{
#ifndef ONLINE_JUDGE
//	freopen("input.txt","r",stdin);
//	freopen("output.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	int ans=0;
	for(int i=26;i>=0;i--)
	{
		for(int j=1;j<=n;j++)
			a[j]&=(1<<(i+1))-1;
		sort(a+1,a+1+n);
		for(int j=1;j<=n;j++)
		{
			if((upper_bound(a+1,a+j,(1<<(i+1))-1-a[j])-lower_bound(a+1,a+j,(1<<i)-a[j]))&1)
				ans^=1<<i;
			if((upper_bound(a+1,a+j,(1<<(i+2))-2-a[j])-lower_bound(a+1,a+j,(1<<(i+1))+(1<<i)-a[j]))&1)
				ans^=1<<i;
		}
	}
	printf("%dn",ans);
	
	
	
	
	
	
	
	
	
	
	
	
	return 0;
}

 

最后

以上就是孝顺小熊猫为你收集整理的CodeForces - 1323D Present(思维+数学)的全部内容,希望文章能够帮你解决CodeForces - 1323D Present(思维+数学)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部