题意:

给你一个集合A,里边有n个正整数,对于所有A的、满足集合内元素异或和为0的子集S,问你∑|S|

n<=1e5,元素<=1e18

首先可以转化问题,不求∑|S|,而是求每个元素属于子集数的和,也就是统计每个元素对答案的贡献

(题解中说根据期望的线性?我不懂期望和这个有啥关系,但是并不影响理解)

既然要求集合中的异或和,线性基就是针对这一类问题的一把好手

先给A求一个基R

对于没有被扔进R的元素,每一个元素对答案的贡献都是2^(n-|R|-1)

因为对于每个元素,先把它选走,剩下的不在R中的元素就可以随便选(也可以都不选),然后基R中一定能找出对应的元素组合把它们搞成0

为什么不用担心R中会有被选出元素相关的贡献没有统计?

注意线性基的性质:基中元素所有子集异或和都不同,保证了不会存在多种从R中选元素的方案,使得和不在R中选的元素异或和为0

接下来需要统计R基中元素对答案的贡献

遍历R中的元素,把它拎出来,给剩下的n-1个元素建个基D

如果被拎出来的元素还能插♂进基D,那就没救了,绝对异或不出0

否则它对答案的贡献就是2^(n-|D|-1),理由同上,不在D中的其他元素可以随便选,而从D中选子集的方案唯一

求基D可以加速,给n个元素中没在基R里的元素建个基B(这名字真鬼 = =)

然后每次把扔掉一个元素的基R和B合并

(线性基最好玩的地方就是用一个小集合代表一个大集合,还能保证不重复不遗漏)

这题我一开始把R中元素拎出来的方法是直接从基R的数组里挑,这种方法是错误的,反例:

7 8 6 8 9 8

如果直接从基里挑会直接把7和6(的第2,3个二进制位)一起挑出来,6本来还可以提供个0110的,但是往基里一放就被7搞没了

正确的姿势应该是开数组把进R基的元素存起来,然后在这个数组里挑出,剩下的重新进基

经验总结:
1.结构化程序设计很重要!之前开了3个数组,然后给每个数组都写个基,debug很难受

用把数组当函数参数的操作就可以只写一套线性基操作,需要用哪个基当参数扔进去即可

2.不要忘记对拍。包括看别人代码找自己错误的时候,有时候眼睛看不出来有啥问题,拍一拍就找到了

写个对拍也没多费事

代码:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define LL long long
LL rd(){LL z=,mk=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')mk=-; ch=getchar();}
while(ch>=''&&ch<=''){z=(z<<)+(z<<)+ch-''; ch=getchar();}
return z*mk;
}
int n; LL a[];
LL bssr[],bssb[],bssd[];
LL ans=,mo=;
bool flg[];
LL q[],hd=;
bool ist(LL x,LL y[]){
for(int i=;i>=;--i)if((LL)<<i&x){
if(!y[i]){
y[i]=x;
++y[];
return true;
}
x^=y[i];
}
return false;
}
bool chck(LL x,LL y[]){
for(int i=;i>=;--i)if((LL)<<i&x)
x^=y[i];
return !x;
}
LL qcp(LL x,int y){
LL z=;
for(;y;y>>=){
if(y&) z=(z*x)%mo;
x=(x*x)%mo;
}
return z;
}
void prvs(){
memset(bssr,,sizeof(bssr));
memset(bssb,,sizeof(bssb));
for(int i=;i<=n;++i) flg[i]=false;
ans=;
hd=;
return ;
}
int main(){
//freopen("ddd.in","r",stdin);
//freopen("ddd.out","w",stdout);
while(~scanf("%d",&n)){
prvs();
for(int i=;i<=n;++i) a[i]=rd();
for(int i=;i<=n;++i){
flg[i]=ist(a[i],bssr);
if(flg[i]) q[++hd]=a[i];
}
if(bssr[]==n){
printf("0\n");
continue;
}
ans+=(n-bssr[])*qcp(,n-bssr[]-)%mo;
for(int i=;i<=n;++i)if(!flg[i])
ist(a[i],bssb);
/*for(int k=0;k<=63;++k)if(bssr[k]){
memset(bssd,0,sizeof(bssd));
for(int i=0;i<=63;++i)
if(i!=k) bssd[i]=bssr[i];
bssd[64]=bssr[64]-1;
for(int i=0;i<=63;++i)if(bssb[i])
ist(bssb[i],bssd);
if(chck(bssr[k],bssd))
ans=(ans+qcp(2,n-bssd[64]-1))%mo;
}*/
for(int k=;k<=hd;++k){
memset(bssd,,sizeof(bssd));
for(int i=;i<=hd;++i)if(i!=k)
ist(q[i],bssd);
for(int i=;i<=;++i)if(bssb[i])
ist(bssb[i],bssd);
if(chck(q[k],bssd))
ans=(ans+qcp(,n-bssd[]-))%mo;
}
printf("%lld\n",ans);
}
return ;
}

【2019牛客多校第一场】XOR的更多相关文章

  1. 2019牛客多校第一场 I Points Division(动态规划+线段树)

    2019牛客多校第一场 I Points Division(动态规划+线段树) 传送门:https://ac.nowcoder.com/acm/contest/881/I 题意: 给你n个点,每个点有 ...

  2. 2019牛客多校第一场E ABBA(DP)题解

    链接:https://ac.nowcoder.com/acm/contest/881/E 来源:牛客网 ABBA 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K,其他语 ...

  3. 2019牛客多校第一场H XOR 线性基模板

    H XOR 题意 给出一组数,求所有满足异或和为0的子集的长度和 分析 n为1e5,所以枚举子集肯定是不可行的,这种时候我们通常要转化成求每一个数的贡献,对于一组数异或和为0.我们考虑使用线性基,对这 ...

  4. 2019牛客多校第一场A-Equivalent Prefixes

    Equivalent Prefixes 传送门 解题思路 先用单调栈求出两个序列中每一个数左边第一个小于自己的数的下标, 存入a[], b[].然后按照1~n的顺序循环,比较 a[i]和b[i]是否相 ...

  5. 2019牛客多校第一场 A.Equivalent Prefixes

    题目描述 Two arrays u and v each with m distinct elements are called equivalent if and only if RMQ(u,l,r ...

  6. 2019 牛客多校第一场 D Parity of Tuples

    题目链接:https://ac.nowcoder.com/acm/contest/881/D 看此博客之前请先参阅吕凯飞的论文<集合幂级数的性质与应用及其快速算法>,论文中很多符号会被本文 ...

  7. 2019牛客多校第一场 E-ABBA(dp)

    ABBA 题目传送门 解题思路 用dp[i][j]来表示前i+j个字符中,有i个A和j个B的合法情况个数.我们可以让前n个A作为AB的A,因为如果我们用后面的A作为AB的A,我们一定也可以让前面的A对 ...

  8. 2019 牛客多校第一场 B Integration

    题目链接:https://ac.nowcoder.com/acm/contest/881/B 题目大意 给定 n 个不同的正整数 ai,求$\frac{1}{\pi}\int_{0}^{\infty} ...

  9. 2019牛客多校第一场E ABBA 贪心 + DP

    题意:问有多少个有(n + m)个A和(n + m)个B的字符串可以凑出n个AB和m个BA. 思路:首先贪心的发现,如果从前往后扫,遇到了一个A,优先把它看成AB的A,B同理.这个贪心策略用邻项交换很 ...

随机推荐

  1. linux查看磁盘是否SSD盘

    命令: cat /sys/block/sda/queue/rotational 注意: 命令中的sba是你的磁盘名称,可以通过df命令查看磁盘,然后修改成你要的 结果: 返回0:SSD盘 返回1:SA ...

  2. 【Python学习之八】设计模式和异常

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 python3.6 一.设计模式1.单例模式确保某一个类只有一个实例, ...

  3. OpenJudge 4152 最佳加法表达式

    总时间限制: 1000ms 内存限制: 65536kB 描述 给定n个1到9的数字,要求在数字之间摆放m个加号(加号两边必须有数字),使得所得到的加法表达式的值最小,并输出该值.例如,在1234中摆放 ...

  4. PHP生成短链接方法

    PHP生成短链接方法方法一:新浪提供了长链接转为短链接的API,可以把长链接转为 t.cn/xxx 这种格式的短链接. API: http://api.t.sina.com.cn/short_url/ ...

  5. Qt qml调试,qml性能分析和优化工具

    QML语言为qt推出的用于界面编程的语言. 1)如何在qt creator中进行调试qml: 以Qt Creator 4.6.2为例: 在qt creator的debug模式下,可以直接在qml中打断 ...

  6. 谈谈php里的IOC控制反转,DI依赖注入(转)

    转自:http://www.cnblogs.com/qq120848369/p/6129483.html 发现问题 在深入细节之前,需要确保我们理解"IOC控制反转"和" ...

  7. AOP实现事务和记录日志

    AOP (Aspect Oriented Programming) 将非功能性需求从功能性需求中剥离出来,解耦并且解决代码复用的问题,比如说权限控制,事务控制,记录操作日志,全局捕获异常等 @Aspe ...

  8. 魔术方法之__call、__callStatic

    1.__call() 作用,当调用不存在的方法时,会调用该方法.实际应用,当程序调用不存在的方法时,意外导致程序终止. .或者当你调用了受保护的或者是私人的方法时,也会自动调用__call方法 结果: ...

  9. 不一样的go语言-athens源码概览

    前言   上一篇文章介绍了athens私服的安装以及vgo download protocol的简要介绍.本文着重介绍go proxy sever的实现原理以及athens是如何实现的. go get ...

  10. Nginx 配置 HTTP 跳转 HTTPS-Linux运维日志

    本文介绍 Nginx 访问 HTTP 跳转 HTTPS 的 4 种配置方式. rewrite Nginx rewrite 有四种 flag: break:在一个请求处理过程中将原来的 url 改写之后 ...