首先,貼一下大佬的部落格(真·大佬)下面的題解也是大佬的,我只是按照我的理解理解了一下............
其次,再了解一下線性基。
很多情況下,只要有關異或運算和求最值,就可以用到線性基。線性基有很多很好的性質,比如說如果有很多個數,我們可以構出這些數的線性基,那麼這個線性基可以通過互相xor,能夠構出原來的數可以相互xor構出的所有的數。所以可以大大減少判斷的時間和次數。同時線性基的任何乙個非空子集都不會使得其xor和為0。
性質 :1. 線性基能相互異或得到原集合的所有相互異或得到的值。 (可以推出線性基內的元素組合與線性基外面的某個元素 組合異或和為0)
2. 線性基是滿足性質1的最小的集合
3.線性基沒有異或和為0的子集。
補充:
線性基的應用:
可以查詢乙個數是否在s的異或集合中
查詢s的異或集合中的最大值。
查詢s的異或集合中的第k大。
線性基的構造:
線性基至多有log a(max)[64]位。如果bi≠0則bi的最高位為第i位。
每次輸入乙個數x,我們從高到低掃,如果最高位上有1,那麼判斷是否有這一位的線性基,如果沒有則令bi=x,當前位賦為x,
否則x=x⊕bi,這就相當於x^線性基當前位。
那麼我們可以發現,插入x的最終結局是:要麼x被選入線性基中;要麼x最後變成了0,說明x已經可以通過線性基中的元素異或出來了。
乙個數如果可以被原來的線性基表示,則在過程中會變成0,否則會被新新增進去線性基。
以下引用了大佬的題解:(加上我的理解奧)
大致題意:給你n個數字,然後讓你求所有滿足異或和為0的子集的大小之和。
首先這個子集大小之和,顯然可以轉換為計算每個數字的出現次數之和。考慮到異或和為0的子集,相當於可以用集合中的一部分數字去表示另外一部分數字,所以很容易想到用線性基解決這個問題。
2.接下來我們考慮基內的r個數字的貢獻。根據線性基的性質,如果對於同樣的n個數字,能夠找到兩個不同的線性基,那麼這兩個線性基中的數字個數一定是相等的。根據這個,對於r個數字中的任意乙個數字,如果用其餘n-1個數字能夠表示(就可以讓該數與其餘n-1各數字異或和為0),那麼說明存在另外乙個線性基能夠表示所有的n個數字,而且這個線性基數字個數也是r,因此這個點的貢獻還是2^;如果用其餘n-1個數字不能表示,那麼說明只要選了這個數字就不存在一種方案使得最後異或和為0,因此貢獻為0.
具體實現的時候,我們沒必要每次重新求n-1個數字的線性基。只需要先求n-r個數字的線性基,然後在這個基的基礎上嘗試新增r-1個數字,這樣複雜度就是o(r^2*63+n*63)。具體見**:
#include#include#include#include#include#include#includeusing namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
const int mod=1e9+7;
typedef long long ll;
struct lbs
inline bool ins(ll x)
} lb1,lb2,lb3;
ll ppow(ll b)
return ans%mod;
}int n;
ll a[maxn];
int vis[maxn];
vectorlb;
int main()
} int r=lb1.tot;
if(n==r){
cout<<0<
2019牛客多校第一場
看到這裡我還能說什麼呢?自己慢慢證吧 就是這個 而 了 大佬們的結論是 三角形面積的22倍。我.手動膜拜。不會證.while true try x1,y1,x2,y2,x3,y3 map int,input split s abs x1 y2 x2 y1 x2 y3 x3 y2 x3 y1 x1 y...
2019 牛客多校 第一場
a 題意 就是兩個陣列,找最大的p,使對於1到p的所有子區間都保證最小值的下標相同 題解 每次往後加乙個值 第i 1位 都會多出 i 個區間,當a i 1 大於max a 1 a i 時沒有影響,當a i 小於max a 1 a i 時,因為a i 1 的加入會導致區間的rmq l到r 的 最小值的...
牛客暑期多校第一場 E Removal dp
原題要求去掉m個元素後不同的子串行個數,可轉化為求,長度為n m的不同的子串行的個數。dp i j 表示以數字i結尾的長度為j的子串行個數,ans j 表示長度為j的子串行個數。列舉序列,因為只要求ans n m 假設當前是第i個數字,那麼更新時只需要更新 i m,i 即可,因為更小的長度的子串行不...