2019年牛客多校H题XOR
登录—专业IT笔试面试备考平台_牛客网
https://ac.nowcoder.com/acm/contest/881/H?&headNav=acm
题目链接
题意
求个数中子集内所有数异或为的子集大小之和。
思路
对于子集大小我们不好维护,因此我们可以转换思路变成求每个数的贡献。
首先我们将所有数的线性基的基底求出来(设秩为),然后非基地元素的贡献就是,即选择这个数然后其他所有非基底元素都可以选择或者不选择两种方法,选择非基底元素后我们再从基底里面挑出能过把它异或为的数选出来就可以达到题目的要求。
对于基底元素,我们将非基底的个元素再跑一个线性基出来,然后用中除去外的剩余元素和构成的新的线性基来进行选择看能不能将消掉(理由同上),如果可以消掉那么的贡献是。
注意后面枚举要用最初始题目给的数而不能用中的数,反例:
如果直接从基里挑会直接把和(的第个二进制位)一起挑出来,本来还可以提供个的,但是往基里一放就被7搞没了。
我说的可能不太清楚,那么可以看这篇博客~
代码实现如下
#include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cassert> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #include <unordered_map> using namespace std; typedef long long LL; typedef pair<LL, LL> pLL; typedef pair<LL, int> pLi; typedef pair<int, LL> pil;; typedef pair<int, int> pii; typedef unsigned long long uLL; #define lson rt<<1 #define rson rt<<1|1 #define lowbit(x) x&(-x) #define name2str(name) (#name) #define bug printf("*********\n") #define debug(x) cout<<#x"=["<<x<<"]" <<endl #define FIN freopen("D://Code//in.txt","r",stdin) #define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8; const int mod = 1000000007; const int maxn = 1e5 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3fLL; int n, r, tot; bool vis[maxn]; vector<LL> vec; LL a[maxn], b[105], other[105], tmp[105]; LL qpow(LL x, int n) { LL res = 1; while(n) { if(n & 1) res = res * x % mod; x = x * x % mod; n >>= 1; } return res; } bool ins(LL x, LL base[]) { for(int i = 63; i >= 0; --i) { if(x & (1LL << i)) { if(base[i]) x ^= base[i]; else { base[i] = x; return true; } } } return false; } int main() { while(~scanf("%d", &n)) { r = tot = 0; vec.clear(); for(int i = 0; i <= 63; ++i) b[i] = other[i] = 0; for(int i = 1; i <= n; ++i) { scanf("%lld", &a[i]); vis[i] = 0; if(ins(a[i], b)) vis[i] = 1, ++r, vec.emplace_back(a[i]); } if(r == n) { printf("0\n"); continue; } LL ans = qpow(2, n - r - 1) * (n - r) % mod;; for(int i = 1; i <= n; ++i) { if(vis[i]) continue; ins(a[i], other); } for(int i = 0; i < vec.size(); ++i) { tot = 0; for(int j = 0; j <= 63; ++j) tmp[j] = 0; for(int j = 0; j < vec.size(); ++j) { if(i == j) continue; if(ins(vec[j], tmp)) ++tot; } for(int j = 0; j <= 63; ++j) { if(other[j] && ins(other[j], tmp)) ++tot; } if(!ins(vec[i], tmp)) { ans = (ans + qpow(2, n - tot - 1)) % mod; } } printf("%lld\n", ans); } return 0; }
```