題目就不翻譯了吧,應該寫的很清楚了。。。html
首先 $,$ 不懂線性基的能夠戳這裏。知道了線性基$,$ 可是歷來沒有寫過線性基和圖論相結合的$,$ 能夠戳這裏。c++
好$,$ 點完了這些前置技能以後,咱們就能夠來愉快的切題啦!優化
類比**$[WC$ $2011]$ 最大$xor$和路徑**$,$ 咱們確定要找環$,$ 找完環後再用環去構造線性基$,$ 由於仍是那句話嘛$:$ 任何一條複雜路徑$,$ 都能有起始兩點的一條簡單路徑再加上若干個環組成。spa
那麼接下來的問題就是$:$如何求出亦或值的和?翻譯
$en$~~~,直接依據線性基,求出能夠被這個線性基構造出的全部亦或值的和,而後相加,呃,是個好方法。code
惋惜$,$ 很不幸$,$ $xor$不知足分配律。而後我又左思右想了2天,終於找到了**「$n$個數中,任取幾個數的亦或和的和」**這個問題的$O(n6363)$的作法,高興了好一陣子,而後發現。。。哎$,$ 如今想一想仍是難受啊。htm
而後痛定思痛$,$ 改變視角——$woc$,原來這麼簡單$!$blog
再也不考慮每一對數的$xor$和,咱們改變目標 $,$去求:對於每一對點的每一位,有多少種方案能使該位的$xor$和位1。get
對於咱們原先就求出來的$d[1]$到$d[n]$ $($就是各個點到1號點的一條簡單路徑的$xor$和$)$ $,$ 咱們要想求出$u$到$v$的一條簡單路徑$,$ 只須要用$d[u]$ $xor$ $d[v]$便可$,$ 由於重複走到路徑會由於$xor$操做而抵消掉。it
若線性基中有$cnt$個非零位,則一共會產生$2^{cnt}$個不一樣的$xor$值。
知道了這些之後$,$ 咱們就能夠開始討論了$:$
$1.$ $d[u]$ $xor$ $d[v]$第$k$位爲1:這樣的話,咱們就須要不取第$k$個線性基$($由於只有第$k$位爲1了纔會對答案產生貢獻嘛$!$ $)$ $,$ 這樣的話,該項對於答案的貢獻即爲$:$ $2^{k}*2^{cnt-1}$。
$2.$ $d[u]$ $xor$ $d[v]$第$k$位爲0$:$ 顯然,必定要取$k$個線性基$,$ 對答案的貢獻即爲$:$ $2^k*2^{cnt-1}$。
儘管這樣$,$ 時間複雜度依然是$O(n^2*63)$的$,$ 吃不消$,$ 那麼哪裏還有優化的空間呢$?$
注意到$,$ $d[i]$第$k$位的值是固定的$,$ 那麼咱們就能夠不單獨討論$"d[u]$ xor $d[v]"$對於答案的貢獻$,$ 直接討論$d[u]$對於答案的貢獻。
先統計出第$k$位爲$0$的數的個數$,$ 咱們將其記爲$x$ $,$ 再統計出第$k$位爲$1$的數的個數$,$ 記爲$y$ $,$ 總共有$point$個點。
分爲$4$種狀況討論$:$
$1.$ $d[i]$的第$k$位爲$1$ $,$ 線性基中有第$k$位爲$1$的數$:$ 此時咱們有兩種選擇:$a.$ 選線性基中的$,$ 另外一個點選擇第$k$位爲$0$的。 $b.$ 不選線性基中的$,$ 另外一個點選擇第$k$位爲$1$的。整體對於答案的貢獻爲:$2^k2^{cnt-1}(point-1)$ $,$ 減$1$就是爲了把本身給去掉。
$2.$ $d[i]$的第$k$位爲$1$ $,$ 線性基中沒有第$k$位爲$1$的數$:$ 這個時候另外一個點只能取第$k$位爲$0$的$,$ 因此總貢獻爲$:$ $2^k*2^{cnt}*x$。
$3.$ $d[i]$的第$k$位爲$0$ $,$ 線性基中有第$k$位爲$1$的數$:$ 同樣的$,$ 兩種選擇$:$ $a.$ 選線性基中的$,$ 另外一個點選擇第$k$位爲$0$的。 $b.$ 不選線性基中的$,$ 另外一個點選擇第$k$位爲$1$的。總貢獻爲$:$ $2^k2^{cnt-1}(point-1)$。
$3.$ $d[i]$的第$k$位爲$0$ $,$ 線性基中沒有第$k$位爲$1$的數$:$ 另外一個點只能取第$k$位爲$1$的$,$ 總貢獻$:$ $2^k*2^{cnt}*y$。
#include<bits/stdc++.h> #define ll long long using namespace std; const ll N=100005,M=400005,p=1e9+7,inv=500000004; ll b[65],dist[M],d[N],a[N],two[65],s[N],z,ans,cnt,point; int head[N],vet[M],nxt[M],c[65],n,m,x,y,tot; bool vis[N],used[M]; void add(int x,int y,ll z){ nxt[++tot]=head[x]; vet[tot]=y; head[x]=tot; dist[tot]=z; } void insert(ll x){ for (int i=62;i>=0;i--) if (x>>i) if (b[i]) x^=b[i]; else {b[i]=x; break;} } void dfs(int u){ a[++point]=d[u]; vis[u]=true; for (int i=head[u];i;i=nxt[i]){ int v=vet[i]; if (!vis[v]){ d[v]=d[u]^dist[i]; dfs(v); } else if (!used[i^1]){ used[i^1]=true; insert(d[u]^d[v]^dist[i]); } } } ll calc(){ ll ans=0; for (int j=0;j<=62;j++){ ll x=0,y=0,flag=0; for (int i=1;i<=point;i++) if (a[i]>>j&1) x++; else y++; for (int i=0;i<=62;i++) if (b[i]>>j&1) flag=1; for (int i=1;i<=point;i++) if (a[i]>>j&1) if (flag) (ans+=two[cnt-1]*(ll)(point-1)%p*two[j]%p)%=p; else (ans+=two[cnt]*y%p*two[j]%p)%=p; else if (flag) (ans+=two[cnt-1]*(ll)(point-1)%p*two[j]%p)%=p; else (ans+=two[cnt]*x%p*two[j]%p)%=p; } return ans; } int main(){ scanf("%d %d",&n,&m); tot=1; for (int i=1;i<=m;i++){ scanf("%d %d %lld",&x,&y,&z); add(x,y,z); add(y,x,z); } two[0]=1; for (int i=1;i<=64;i++) two[i]=two[i-1]*2%p; for (int i=1;i<=n;i++) if (!vis[i]){ memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); point=0,cnt=0; dfs(i); for (int j=0;j<=62;j++) cnt+=(b[j]>0); (ans+=calc())%=p; } ans=ans*inv%p; printf("%lld\n",ans); return 0; }