题目
n(n<=1e5)个点,m(m<=n+41)条边的仙人掌,
保证最多42个环,每条边有一个边权w(w<=1e5),
求异或权值最小的生成树,即最终的答案=选中的边权的异或和,令该答案最小,
输出答案,及得到该答案的方案数,答案模1e9+7
思路来源
https://blog.csdn.net/u013534123/article/details/103307091
题解
仙人掌找环,42个环,把不在环上的边异或起来得到一个值,
上述43个数组做一个FWT_xor,最终得到最小的不为0的方案数即为答案
但是可能会存在mod1e9+7恰为0,但实际不为0的情况,
赛中写了个代码2,exist数组强制把有值的重新标记为1,
这样不会出现求和正好为1e9+7,然后模1e9+7得0的情况
赛后学了个代码1,可以再新开一场模数,类似双哈希,只要有一个不为0就说明有方案
后者FWT的次数更少,所以更快
代码1
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
typedef long long ll;
#define pb push_back
#define fi first
#define se second
const int N=1<<17;
const int MOD=1e9+7,mod2=1e9+9;
const int inv2=(MOD+1)/2;
int n,m,u,v,w,vis[N],dfn[N],y,ans,c[44],t;
P now[N];
vector<P>e[N];
ll cnt[44][N],ex[44][N],res;
void FWT_xor(ll *a,int opt,int MOD){
for(int i=1;i<N;i<<=1)
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k){
int X=a[j+k],Y=a[i+j+k];
a[j+k]=(X+Y)%MOD;a[i+j+k]=(X+MOD-Y)%MOD;
if(opt==-1)a[j+k]=1ll*a[j+k]*inv2%MOD,a[i+j+k]=1ll*a[i+j+k]*inv2%MOD;
}
}
void dfs(int u,int fa,int ww){
vis[u]=1;
now[++y]=P(u,ww);
dfn[u]=y;
for(auto &x:e[u]){
int v=x.fi,w=x.se;
if(v==fa)continue;
if(!vis[v]){
dfs(v,u,w);
}
else if(vis[v]==1){
++t;
cnt[t][w]++;ex[t][w]++;
for(int i=dfn[u];i>dfn[v];--i){
int z=now[i].se;
cnt[t][z]++;
ex[t][z]++;
}
}
}
--y;
vis[u]=2;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
scanf("%d%d%d",&u,&v,&w);
ans^=w;
e[u].pb(P(v,w));
e[v].pb(P(u,w));
}
for(int i=1;i<=n;++i){
if(!vis[i]){
dfs(i,-1,0);
}
}
cnt[0][ans]=ex[0][ans]=1;
FWT_xor(cnt[0],1,MOD);FWT_xor(ex[0],1,mod2);
for(int i=1;i<=t;++i){
FWT_xor(cnt[i],1,MOD);FWT_xor(ex[i],1,mod2);
for(int j=0;j<N;++j){
cnt[i][j]=1ll*cnt[i-1][j]*cnt[i][j]%MOD;
ex[i][j]=1ll*ex[i-1][j]*ex[i][j]%mod2;
}
}
FWT_xor(cnt[t],-1,MOD);FWT_xor(ex[t],-1,mod2);
for(int i=0;i<N;++i){
if(!cnt[t][i] && !ex[t][i])continue;
printf("%d %lld",i,cnt[t][i]);
break;
}
return 0;
}
代码2
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> P;
typedef long long ll;
#define pb push_back
#define fi first
#define se second
const int N=1<<17;
const int MOD=1e9+7;
const int inv2=(MOD+1)/2;
int n,m,u,v,w,vis[N],dfn[N],y,ans,c[44],t;
P now[N];
vector<P>e[N];
ll cnt[44][N],ex[44][N],res;
void FWT_xor(ll *a,int opt){
for(int i=1;i<N;i<<=1)
for(int p=i<<1,j=0;j<N;j+=p)
for(int k=0;k<i;++k){
int X=a[j+k],Y=a[i+j+k];
a[j+k]=(X+Y)%MOD;a[i+j+k]=(X+MOD-Y)%MOD;
if(opt==-1)a[j+k]=1ll*a[j+k]*inv2%MOD,a[i+j+k]=1ll*a[i+j+k]*inv2%MOD;
}
}
void dfs(int u,int fa,int ww){
vis[u]=1;
now[++y]=P(u,ww);
dfn[u]=y;
for(auto &x:e[u]){
int v=x.fi,w=x.se;
if(v==fa)continue;
if(!vis[v]){
dfs(v,u,w);
}
else if(vis[v]==1){
++t;
cnt[t][w]++;
for(int i=dfn[u];i>dfn[v];--i){
int z=now[i].se;
cnt[t][z]++;
}
}
}
--y;
vis[u]=2;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
scanf("%d%d%d",&u,&v,&w);
ans^=w;
e[u].pb(P(v,w));
e[v].pb(P(u,w));
}
for(int i=1;i<=n;++i){
if(!vis[i]){
dfs(i,-1,0);
}
}
if(!t){
printf("%d 1\n",ans);
return 0;
}
if(t==1){
int tmp=100000000;
for(int i=N-1;i>=0;--i){
if(!cnt[1][i])continue;
if((ans^i)<tmp){
tmp=ans^i;
res=cnt[1][i];
}
else if((ans^i)==tmp){
res+=cnt[1][i];
}
}
printf("%d %lld\n",tmp,res);
return 0;
}
for(int i=1;i<=t;++i){
for(int j=1;j<N;++j){
if(cnt[i][j]){
ex[i][j]=1;
}
}
}
FWT_xor(cnt[1],1);FWT_xor(ex[1],1);
for(int i=2;i<=t;++i){
FWT_xor(cnt[i],1);FWT_xor(ex[i],1);
for(int j=0;j<N;++j){
cnt[i][j]=1ll*cnt[i-1][j]*cnt[i][j]%MOD;
ex[i][j]=1ll*ex[i-1][j]*ex[i][j]%MOD;
}
FWT_xor(ex[i],-1);
for(int j=0;j<N;++j){
if(ex[i][j])ex[i][j]=1;
}
FWT_xor(ex[i],1);
}
FWT_xor(cnt[t],-1);FWT_xor(ex[t],-1);
int tmp=100000000;
for(int i=N-1;i>=0;--i){
if(!ex[t][i])continue;
if((ans^i)<tmp){
tmp=ans^i;
res=cnt[t][i];
}
else if((ans^i)==tmp){
res+=cnt[t][i];
}
}
printf("%d %lld\n",tmp,res);
return 0;
}