概述
题目链接:点击查看
题目大意:给出一个数列 a ,求出
题目分析:如果暴力的话显然时间复杂度是 n * n 的,我们应该想办法去优化,比赛的时候想用线段树,但是不会在维护异或的前提下区间加法,也想过用矩阵维护,但丝毫没什么用呀,队友想到了可以按位维护,也就是维护26个线段树,我觉得太麻烦了就放弃这个题了,补题的时候看了题解,感觉题解已经说的很明白了,在这里再记录一下吧,感觉还是自己太菜了,需要多做题长见识
题解的意思是,可以按位维护,因为异或等位运算,最大的特点就是,每一位都可以视为独立的个体,互不影响,互不干预,这样我们在单独处理第 k 位的时候,因为要计算 a[ i ] + a[ j ] 后再进行异或,所以显然某个数大于 的部分是没有贡献的,我们可以先让每个数对 取模,因为后面我们需要二分查找,所以取模后对于整个数组排一下序,到此为止,所有的 a 数组中的每个元素的取值范围都是 ,显然 a[ i ] + a[ j ] 的取值范围是 ,不难看出第 k 位为 1 时的 a[ i ] + a[ j ] 的取值范围为 ,这样我们就可以固定下来 i ,从而二分查找符合条件的 j ,记录下来有多少对 ( i , j ) 可以对第 k 位做出贡献,因为 a[ i ] + a[ j ] 的范围上面已经确定下来了,那么当 a[ i ] 确定时,a[ j ]的范围也就非常容易确定了: 。如果 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(思维+数学)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复