zoukankan      html  css  js  c++  java
  • 题解 洛谷 P5406 【[THUPC2019]找树】

    对于一种权值的生成树的存在性,可以将其转化为该权值的生成树个数的计数问题。

    先考虑运算若不是位运算,是加法的情况,要怎么处理。对于边权为 (v) 的一条边,将其边权赋为 (x^v),然后应用矩阵树定理,若所得行列式的第 (i) 次项系数不为 (0),即生成树个数不为 (0),就说明存在边权和为 (i) 的生成树。

    同样,对于位运算也是适用的。分别考虑每种边权,对于每种边权都构造出基尔霍夫矩阵,沃尔什变换后求解行列式,然后记录每种边权求得的行列式的值,对其逆沃尔什变换后即为答案。

    因为每一位的位运算类型不同,所以沃尔什变换时要考虑每一位的类型,应用对应的变换。在应用矩阵树定理时还需模一个大质数。

    (code:)

    #include<bits/stdc++.h>
    #define maxn 75
    #define maxv 5010
    #define p 998244353
    #define inv2 499122177
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,m,w,all;
    ll t[maxn][maxn][maxv],a[maxn][maxn],ans[maxv];
    char s[maxn];
    void FWT(ll *a,int type)
    {
        for(int len=1,pos=1;len<all;len<<=1,++pos)
        {
            for(int i=0;i<all;i+=len<<1)
            {
                for(int j=i;j<i+len;++j)
                {
                    if(s[pos]=='|') a[j+len]=(a[j+len]+a[j]*type+p)%p;
                    if(s[pos]=='&') a[j]=(a[j]+a[j+len]*type+p)%p;
                    if(s[pos]=='^')
                    {
                        ll x=a[j],y=a[j+len];
                        a[j]=(x+y)%p,a[j+len]=(x-y+p)%p;
                        if(type!=1) a[j]=a[j]*inv2%p,a[j+len]=a[j+len]*inv2%p;
                    }
                }
            }
        }
    }
    ll qp(ll x,ll y)
    {
        ll v=1;
        while(y)
        {
            if(y&1) v=v*x%p;
            x=x*x%p,y>>=1;
        }
        return v;
    }
    ll det()
    {
        ll v=1;
        for(int i=1;i<n;++i)
        {
            int pos=i;
            for(int j=i+1;j<n;++j)
            {
                if(a[j][i])
                {
                    pos=j;
                    break;
                }
            }
            if(pos!=i) swap(a[i],a[pos]),v*=-1;
            if(!a[i][i]) return 0;
            ll inv=qp(a[i][i],p-2);
            for(int j=i+1;j<n;++j)
            {
                ll d=a[j][i]*inv%p;
                for(int k=i;k<n;++k)
                    a[j][k]=(a[j][k]-a[i][k]*d%p+p)%p;
            }
            v=v*a[i][i]%p;
        }
        return v;
    }
    int main()
    {
        read(n),read(m);
        scanf("%s",s+1),w=strlen(s+1),all=1<<w;
        for(int i=1;i<=m;++i)
        {
            int x,y,v;
            read(x),read(y),read(v);
            t[x][x][v]++,t[y][y][v]++;
            t[x][y][v]--,t[y][x][v]--;
        }
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                FWT(t[i][j],1);
        for(int k=0;k<all;++k)
        {
            for(int i=1;i<=n;++i)
                for(int j=1;j<=n;++j)
                    a[i][j]=t[i][j][k];
            ans[k]=det();
        }
        FWT(ans,-1);
        for(int i=all-1;i>=0;--i)
        {
            if(ans[i])
            {
                printf("%d",i);
                return 0;
            }
        }
        puts("-1");
        return 0;
    }
    
  • 相关阅读:
    Java日志框架
    分布式任务并发调度
    并发(三) CountDownLatch
    并发(二)CyclicBarrier
    并发(一) Semaphore
    MySql
    Hash
    由一个序列化框架的更换引发的问题
    navicat 12 激活
    Spring security
  • 原文地址:https://www.cnblogs.com/lhm-/p/13401525.html
Copyright © 2011-2022 走看看