CF724G 【Xor-matic Number of the Graph】

  • 題目就不翻譯了吧,應該寫的很清楚了。。。html

  • 首先 $,$ 不懂線性基的能夠戳這裏。知道了線性基$,$ 可是歷來沒有寫過線性基和圖論相結合的$,$ 能夠戳這裏c++

  • 好$,$ 點完了這些前置技能以後,咱們就能夠來愉快的切題啦!優化

正片$:$

  • 類比**$[WC$ $2011]$ 最大$xor$和路徑**$,$ 咱們確定要找環$,$ 找完環後再用環去構造線性基$,$ 由於仍是那句話嘛$:$ 任何一條複雜路徑$,$ 都能有起始兩點的一條簡單路徑再加上若干個環組成spa

  • 那麼接下來的問題就是$:$如何求出亦或值的和?翻譯

  • $en$~~~,直接依據線性基,求出能夠被這個線性基構造出的全部亦或值的和,而後相加,呃,是個好方法。code

  • 惋惜$,$ 很不幸$,$ $xor$不知足分配律。而後我又左思右想了2天,終於找到了**「$n$個數中,任取幾個數的亦或和的和」**這個問題的$O(n6363)$的作法,高興了好一陣子,而後發現。。。哎$,$ 如今想一想仍是難受啊。htm

  • 而後痛定思痛$,$ 改變視角——$woc$,原來這麼簡單$!$blog

  • 再也不考慮每一對數的$xor$和,咱們改變目標 $,$去求:對於每一對點的每一位,有多少種方案能使該位的$xor$和位1get

  • 對於咱們原先就求出來的$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$。

  • 最後別忘記給答案除個$2$就$OK$啦$!($要用逆元哦$)$

代碼$:$

#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;
}
相關文章
相關標籤/搜索