给你一个包含最多42个环的仙人掌图,让你找最小异或和生成树,并且输出方案数。
由于只有42个环,所以我们可以暴力找出每一个环。
由于是要找生成树,所以肯定是每个环中选择一条边去掉,然后把这些边的权值异或起来即可。考虑如果某个环有x个点,那么最多就会有x个不同的异或和数值,我们可以把这些数值用一个多项式记下来,这样总共就有42个多项式。
然后对于不在环上的边,直接求出异或和,也用一个多项式来表示。总共最多43个多项式,把他们用异或卷起来就是最后的答案。我们只需要找第一个数值也即方案数不为0的位置,对应数值就是最小的异或和。考虑到取模之后方案数可能为0,所以用再用另一个模数做一次,最后只要在其中一个模数下方案数不为0就说明此方案可行。
#include
#define INF 0x3f3f3f3f
#define eps 1e-5
#define pi 3.141592653589793
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<" : "<
#define mem(x,y) memset(x,0,sizeof(int)*(y+3))
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
const int N = 1<<17;
const int mod1 = 1e9 + 7;
const int mod2 = 998244353;
std::vector<pair<int,int> > G[N];
std::vector<std::vector<int> > V;
int fa[N],w[N],dfn[N],idx,sum;
int f[N<<1],g[N<<1],ff[N<<1],gg[N<<1],n,m;
void dfs(int x,int f)
{
dfn[x]=++idx;
for(auto y:G[x])
{
if (y.fi==f) continue;
if (dfn[y.fi]>dfn[x])
{
int tmp=y.se;
for(int i=y.fi;i!=x;i=fa[i])
tmp^=w[i];
std::vector<int> v;
v.pb(tmp^y.se);
for(int i=y.fi;i!=x;i=fa[i])
v.pb(tmp^w[i]);
V.pb(v); sum^=tmp;
} else if (!dfn[y.fi])
{
fa[y.fi]=x; w[y.fi]=y.se;
dfs(y.fi,x);
}
}
}
void FWT_xor(int *a,int opt,int MOD)
{
int inv2 = (MOD + 1) / 2;
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;
}
}
int main(int argc, char const *argv[])
{
scc(n,m);
for(int i=1;i<=m;i++)
{
int x,y,w; sccc(x,y,w);
G[x].pb({y,w}); G[y].pb({x,w});
sum^=w;
}
dfs(1,0);
f[sum]=g[sum]=1;
FWT_xor(f,1,mod1);
FWT_xor(g,1,mod2);
for(auto v:V)
{
memset(ff,0,sizeof(ff));
memset(gg,0,sizeof(gg));
for(auto x:v) ff[x]++,gg[x]++;
FWT_xor(ff,1,mod1);
FWT_xor(gg,1,mod2);
for(int i=0;i<1<<17;i++)
{
f[i]=(LL)f[i]*ff[i]%mod1;
g[i]=(LL)g[i]*gg[i]%mod2;
}
}
FWT_xor(f,-1,mod1);
FWT_xor(g,-1,mod2);
for(int i=0;i<1<<17;i++)
if (f[i]||g[i])
{
printf("%d %d\n",i,f[i]);
break;
}
return 0;
}