CodeForces - 1218D Xor Spanning Tree(仙人掌图找环 + FWT)

CodeForces - 1218D Xor Spanning Tree(仙人掌图找环 + FWT)_第1张图片
CodeForces - 1218D Xor Spanning Tree(仙人掌图找环 + FWT)_第2张图片

大致题意

给你一个包含最多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;
}

你可能感兴趣的:(CodeForces,FFT/NTT/FWT,CodeForces,FWT,仙人掌图)