帶勁的and和 (並查集找聯通 二進位制運算)

2021-09-13 01:57:06 字數 2167 閱讀 6473

度度熊專門研究過「動態傳遞閉包問題」,他有一萬種讓大家爆蛋的方法;但此刻,他只想出一道簡簡單單的題——至繁,歸於至簡。 

度度熊有一張n個點m條邊的**無向圖**,第ii個點的點權為vivi。 

如果圖上存在一條**路徑**使得點ii可以走到點jj,則稱i,ji,j是**帶勁**的,記f(i,j)=1f(i,j)=1;否則f(i,j)=0f(i,j)=0。顯然有f(i,j)=f(j,i)f(i,j)=f(j,i)。 

度度熊想知道求出: 

∑n−1i=1∑nj=i+1f(i,j)×max(vi,vj)×(vi&vj)∑i=1n−1∑j=i+1nf(i,j)×max(vi,vj)×(vi&vj) 

其中&&是c++中的and位運算子,如1&3=1, 2&3=2。 

請將答案對109+7109+7取模後輸出。

input

第一行乙個數,表示資料組數tt。 

每組資料第一行兩個整數n,mn,m;第二行nn個數表示vivi;接下來mm行,每行兩個數u,vu,v,表示點uu和點vv之間有一條無向邊。**可能有重邊或自環。** 

資料組數t=50,滿足: 

- 1≤n,m≤1000001≤n,m≤100000 

- 1≤vi≤1091≤vi≤109。 

其中90%的資料滿足n,m≤1000n,m≤1000。 

output

每組資料輸出一行,每行僅包含乙個數,表示帶勁的and和。 

sample input

1

5 53 9 4 8 9

2 11 3

2 11 2

5 2

sample output

99
題意:中文題嘛....其實就是找相互連通的頂點 的公式和(兩者之間的最大值 * 兩者的 & 運算值    求和)。

思路:很容易想到用並查集找到相互連通的頂點。之後就是在集合裡運算了...直接暴力求和?結果當然是tle了。

那麼我們來換一種思路:在這裡,我們是要求 兩者之間的最大值 * 兩者的 & 運算值    求和;對於最大值,我們可以從小到大排一下序,那麼此時我們求的就是:(好醜...)

接下來我們再看十進位制乘二進位制 乘法運算emmmm....orz....

接下來我們再看 & 運算emmmm....orz....

好了,重點來了!!!!因為我們先對集合內的元素進行排序,公式可以轉化成圖一那樣:也就是說對於第n個數,它要乘以

(1--> n-1 中每一數和它 & 的和)。那麼我們就可以開乙個dp陣列記錄,到達第n個數之前,每一位(二進位制)出現的次數,因為 &運算中(兩個都1 結果才為 1),如果第n個數的第 k 位(二進位制)為 1 的話,我們就需要看看前面的那些數中有沒有第k位為1的數,假設有dp[k]個,那麼這個數(xn)就可以利用十進位制乘二進位制求和了: (xn * dp[k]  *  (1**如下:

#include#include#include#include#define n 100010

#define ll long long

using namespace std;

const int mod = 1e9+7;

int n,f[n],a[n];

vectorv[n];

void init()

}int getf(int x)

void merge(int x,int y)

int main()

for(int i=1; i<=n; i++)

ll sum=0,dp[50];

for(int i=1; i<=n; i++) }}

}}printf("%lld\n",sum);}}

HDU 6411 帶勁的and和 並查集 位運算

題目鏈結 略n 1e5的資料規模肯定是不能直接列舉兩個相連的點的。既然題目中用到了位運算,就要從二進位制的角度來考慮。對於乙個連通分量,我們將其中的所有點按照權值排序,這時候再暴力列舉的話,肯定是最大的點和其他點分別來做與運算,然後次大的點和比它小的點做與運算。從位運算的角度思考,只有兩個數相同二進...

並查集 優秀的找爹模板題

並查集的操作有三步,初始化,查詢祖先與合併。既然並查集是來查詢祖先的,那麼初始化就必然是讓每個點的祖先指向自己 for int i 1 i n i fa i i 查詢操作就是不斷地向上走,直到找到祖先為止 while x fa x x fa x 合併操作就是把乙個節點的祖先變為另乙個節點的祖先。fa...

並查集判斷環 並查集的路徑壓縮 和 帶秩優化

1.判斷環 參考部落格 思路 1.將用過的路徑連起來成為乙個集合,記錄下來 2.如果連通的兩個邊屬於乙個集合,那麼這個並查集就形成了乙個環 燈神 如果刪除2,4邊 可將2,4這條邊刪除測試 是否正確 如果刪除此邊則不會出現環記得將6改為5 initialise parent for int i 0 ...