割
给定一个无向简单图(即无重边无自环),每条边都有一个权值。
这个图的一个割,指的是将它的点集划分为两个不重不漏的集合 (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