zoukankan      html  css  js  c++  java
  • CF724G 【Xor-matic Number of the Graph】

    • 题目就不翻译了吧,应该写的很清楚了。。。

    • 首先 (,) 不懂线性基的可以戳这里。知道了线性基(,) 但是从来没有写过线性基和图论相结合的(,) 可以戳这里

    • (,) 点完了这些前置技能之后,我们就可以来愉快的切题啦!

    正片(:)

    • 类比([WC) (2011]) 最大(xor)和路径(,) 我们肯定要找环(,) 找完环后再用环去构造线性基(,) 因为还是那句话嘛(:) 任何一条复杂路径(,) 都能有起始两点的一条简单路径再加上若干个环组成

    • 那么接下来的问题就是(:)如何求出亦或值的和?

    • (en)~~~,直接依据线性基,求出可以被这个线性基构造出的所有亦或值的和,然后相加,呃,是个好方法。

    • 可惜(,) 很不幸(,) (xor)不满足分配律。然后我又冥思苦想了2天,终于找到了(n)个数中,任取几个数的亦或和的和”这个问题的(O(n*63*63))的做法,高兴了好一阵子,然后发现。。。哎(,) 现在想想还是难受啊。

    • 然后痛定思痛(,) 改变视角——(woc),原来这么简单(!)

    • 不再考虑每一对数的(xor)和,我们改变目标 (,)去求:对于每一对点的每一位,有多少种方案能使该位的(xor)和位1

    • 对于我们原先就求出来的(d[1])(d[n]) (()就是各个点到1号点的一条简单路径的(xor)()) (,) 我们要想求出(u)(v)的一条简单路径(,) 只需要用(d[u]) (xor) (d[v])即可(,) 因为重复走到路径会因为(xor)操作而抵消掉。

    • 若线性基中有(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^k*2^{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^k*2^{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
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Objective-C传递数据小技巧
    得到当前活动的controller
    ios7去除手势滑动返回
    生活小常识
    通过email分享
    release下去除nslog宏
    AFNetworking VS ASIHTTPRequest
    web服务器和应用服务器
    mac 搭建git服务器
    UIKit基础:14-序列帧动画的简单介绍
  • 原文地址:https://www.cnblogs.com/WR-Eternity/p/10291631.html
Copyright © 2011-2022 走看看