Intersection (线性基)(板子补充)

链接: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;
}
 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章