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;
}
 

 

 

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