zoukankan      html  css  js  c++  java
  • 给定一个无向简单图(即无重边无自环),每条边都有一个权值。

    这个图的一个割,指的是将它的点集划分为两个不重不漏的集合 (S)(T)

    这个割的权值,是所有两个端点分别属于 (S)(T) 的边的权值的异或和(即 (S) 内部的边和 (T) 内部的边都不算)。

    现在问这个图的 割的所有可能的权值 的和是多少。

    由于这个数很大,只需要输出 (9) 位,不足 (9) 位则全部输出。

    输入格式

    第一行两个数 (n)(m) 表示图的点数和边数。
    之后 (m) 行每行 (3) 个数 (x, y, z) 表示一条边的两个端点和这条边的权值。点的编号从 (1)(n)

    输出格式

    一行一个整数表示答案。

    数据范围

    (1le nle 10^5,1le mle min(frac{n(n-1)}{2},2 imes 10^5),0le zle 10^9)


    考场上看成对所有划分数求和了,那个真是没法做...

    考虑所有点都是白色,然后选择一个点染黑,会选择与这个点相连的所有边

    选择任意个不相邻的点染黑,会选择与这些点相连的边

    选择一对相邻的点染黑,那么某条边就不会被选了,可以被刚好异或掉

    因此,设定点权为与它相连的边权的异或和,对点求线性基就可以了

    然后在最后统计答案的时,所有满秩的位置显然可以选 0/1 ,那么其余满秩位置随便选的。

    但是不满秩的位置可能是 0 或者 1,我们一样需要统计非满秩位置的 1,不过当你选择这个非满秩的 1 时,实际上也钦定了某个满秩的位置是 1,所以一样的统计就可以了


    Code:

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    using std::min;
    const int SIZE=1<<21;
    char ibuf[SIZE],*iS,*iT;
    //#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
    #define gc() getchar()
    template <class T>
    void read(T &x)
    {
        x=0;int f=0;char c=gc();
        while(!isdigit(c)) f|=c=='-',c=gc();
        while(isdigit(c)) x=x*10+c-'0',c=gc();
        if(f) x=-x;
    }
    const int N=1e5+10;
    int n,m,yuu[N],aya[30],cnt,base[40];
    ll ans;
    void ins(int x)
    {
        for(int i=30;~i;i--)
            if(x>>i&1)
            {
                if(base[i]) x^=base[i];
                else
                {
                    base[i]=x;
                    return;
                }
            }
    }
    int main()
    {
        read(n),read(m);
        for(int u,v,z,i=1;i<=m;i++)
        {
            read(u),read(v),read(z);
            yuu[u]^=z,yuu[v]^=z;
        }
        for(int i=1;i<=n;i++) ins(yuu[i]);
        for(int i=0;i<=30;i++) cnt+=base[i]>0;
        for(int i=0;i<=30;i++)
        {
            int flag=0;
            for(int j=0;j<30;j++) flag|=base[j]>>i&1;
            if(flag)
                ans+=(1ll<<cnt-1)*(1ll<<i);
        }
        while(ans) aya[++aya[0]]=ans%10,ans/=10;
        for(int i=1;i<=min(aya[0],9);i++)
            printf("%d",aya[aya[0]-i+1]);
        return 0;
    }
    

    2019.6.14

  • 相关阅读:
    2016年3月iOS面试总结
    iOS常用公共方法
    让你的App说出多国语言——iOS开发之本地化(国际化)
    开发中遇到的坑
    Git简明教程
    iOS-打包成ipa的4种方法
    iOS-最全的App上架教程
    android 开源项目
    android 文件缓存工具类
    android 聊天通讯源码
  • 原文地址:https://www.cnblogs.com/butterflydew/p/11022082.html
Copyright © 2011-2022 走看看