链接:https://ac.nowcoder.com/acm/contest/1109/C
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
Special Judge, 64bit IO Format: %lld
题目描述
Bobo has two sets of integers A={a1,a2,…,an}A = \{a_1, a_2, \dots, a_n\}A={a1,a2,…,an} and B={b1,b2,…,bn}B = \{b_1, b_2, \dots, b_n\}B={b1,b2,…,bn}.
He says that x∈span(A)x \in \mathrm{span}(A)x∈span(A) (or span(B)\mathrm{span}(B)span(B)) if and only if there exists a subset of A (or B) whose exclusive-or sum equals to x.
Bobo would like to know the number of x where x∈span(A)x \in \mathrm{span}(A)x∈span(A) and x∈span(B)x \in \mathrm{span}(B)x∈span(B) hold simultaneously.
输入描述:
The input contains zero or more test cases and is terminated by end-of-file. For each test case:
The first line contains an integer n.
The second line contains n integers a1,a2,…,ana_1, a_2, \dots, a_na1,a2,…,an.
The third line contains n integers b1,b2,…,bnb_1, b_2, \dots, b_nb1,b2,…,bn.
* 1≤n≤501 \leq n \leq 501≤n≤50
* 0≤ai,bi<2600 \leq a_i, b_i < 2^{60}0≤ai,bi<260
* The number of test cases does not exceed 5000.
输出描述:
For each case, output an integer which denotes the result.
示例1
输入
2
0 0
0 0
2
1 2
1 3
输出
1
4
备注:
For the second sample, span(A)=span(B)={0,1,2,3}\mathrm{span}(A) = \mathrm{span}(B) = \{0, 1, 2, 3\}span(A)=span(B)={0,1,2,3}.
A和B的都能表示的秩等于A能表示的秩+B能表示的秩序-A和B共同表示的秩。(容斥~)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
class BASE {
static const int DEG = 62;
public:
int tot = 0, n = 0, cnt = 0;
ll d[63], nd[63];
BASE() {
memset(d, 0, sizeof d);
tot = 0; n = 0; cnt = 0;
}
~BASE() {}
void Init() {
memset(d, 0, sizeof d);
tot = 0; n = 0; cnt = 0;
}
void Ins(ll x) {
n++;
for (int i = DEG; i >= 0; i--) {
if (!(x&(1ll << i)))continue;
if (!d[i]) {d[i] = x; cnt++; break;}
x ^= d[i];
}
}
ll Max(ll x) {
ll res = x;
for (int i = DEG; i >= 0; i--) {
res = max(res, res^d[i]);
}
return res;
}
ll Min() {
for (int i = 0; i <= DEG; i++)
if (d[i])
return d[i];
return 0;
}
void Rebuild() {
for (int i = DEG; i >= 0; i--) {
if (d[i] == 0)continue;
for (int j = i - 1; j >= 0; j--) {
if (d[j] == 0)continue;
if (d[i] & (1ll << j)) d[i] ^= d[j];
}
}
for (int i = 0; i <= DEG; i++)
if (d[i]) nd[tot++] = d[i];
}
ll Kth(ll k) {
if (k == 1ll && tot < n)return 0;
if (tot < n)k--;
if (k >= (1ll << tot)) return -1;
ll res = 0;
for (int i = DEG; i >= 0; i--)
if (k&(1ll << i))
res ^= nd[i];
return res;
}
void merge(BASE T) {
for (int i = DEG; i >= 0; i--) {
if (T.d[i] == 0)continue;
Ins(T.d[i]);
}
}
}A, B;
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int n;
while (cin >> n) {
A.Init(); B.Init();
for (int i = 0; i < n; i++) {
long long a;
cin >> a; A.Ins(a);
}
for (int i = 0; i < n; i++) {
long long a;
cin >> a; B.Ins(a);
}
long long res = 1;int sum = 0;
sum = A.cnt + B.cnt;
A.merge(B);
sum -= A.cnt;
while (sum--) {
res *= 2;
}
cout << res << "\n";
}
return 0;
}
补一个更全的板子(其实就是多了一个求交)
struct LB
{
ll d[100];
int tot;
LB()
{
tot = 0;
memset(d, 0, sizeof(d));
}
bool add(ll x)
{
for (int i = 63; ~i; i--)
{
if (x & (1ll << i)) //注意,如果i大于31,前面的1的后面一定要加ll
{
if (d[i])
x ^= d[i];
else
{
d[i] = x;
break; //记得如果插入成功一定要退出
}
}
}
return x > 0; //如果成功插入 返回true;
}
ll Max1(ll x) //与x异或最大值
{
ll ans = x;
for (int i = 63; ~i; i--) //记得从线性基的最高位开始
if ((ans ^ d[i]) > ans)
ans ^= d[i];
return ans;
}
ll Max2() //当前数集能异或出来的最大数字 线性基最大就令x = 0 - 贪心构造(二进制下高位的1对于答案的贡献要比下面所有的位数都为1的贡献还要大)
{
ll ans = 0;
for (int i = 63; ~i; i--)
if ((ans ^ d[i]) > ans)
ans ^= d[i];
return ans;
}
ll Min1(ll x) //与x异或最小值
{
ll ans = x;
for (int i = 63; ~i; i--)
if ((ans ^ d[i]) < ans)
ans ^= d[i];
return ans;
}
ll Min2() //线性基最小 -直接取出最后一位不是零的数字
{
for (int i = 0; i <= 63; i++)
if (d[i])
return d[i];
return 0;
}
void rebuild() //处理线性基 变成阶梯型
{
for (int i = 1; i <= 63; i++)
for (int j = 1; j <= i; j++)
if (d[i] & (1ll << (j - 1)))
d[i] ^= d[j - 1];
}
ll k_th(ll k) //第k小
{
if (k == 1 && tot < n)
return 0; //特判一下,假如k=1,并且原来的序列可以异或出0,就要返回0,tot表示线性基中的元素个数,n表示序列长度
if (tot < n)
k--; //类似上面,去掉0的情况,因为线性基中只能异或出不为0的解
if (k >= (1ll << tot)) //线性基包含的数为(1<<tot)-1(组合数之和减去不取的一种情况) tot为线性基大小 返回-1为找不到k_th的数
return -1;
ll ans = 0;
for (int i = 0; i <= 63; i++)
if (d[i] != 0)
{
if (k % 2 == 1)
ans ^= d[i];
k /= 2;
}
if (k != 0)
return -1;
return ans;
}
};
LB merge(LB &n1, LB &n2) //线性基合并
{
LB ret = n1;
for (int i = 0; i <= 63; i++)
if (n2.d[i])
ret.add(n2.d[i]);
return ret;
}
LB Merge(LB A, LB B)
{
LB All, C, D;
for (int i = 63; ~i; i--)
{
All.d[i] = A.d[i];
D.d[i] = 1ll << i;
}
for (int i = 63; ~i; i--)
{
if (B.d[i])
{
ll v = B.d[i], k = 0;
bool can = true;
for (int j = 63; ~j; j--)
{
if (v & (1ll << j))
{
if (All.d[j])
{
v ^= All.d[j];
k ^= D.d[j];
}
else
{
can = false;
All.d[j] = v;
D.d[j] = k;
break;
}
}
}
if (can)
{
ll v = 0;
for (int j = 63; ~j; j--)
if (k & (1ll << j))
v ^= A.d[j];
C.add(v);
}
}
}
C.rebuild();
return C;
}