zoukankan      html  css  js  c++  java
  • 【uoj#94】【集训队互测2015】胡策的统计(集合幂级数)

      题目传送门:http://uoj.ac/problem/94

      这是一道集合幂级数的入门题目。我们先考虑求出每个点集的连通生成子图个数,记为$g_S$,再记$h_S$为点集$S$的生成子图个数,容易发现,$h_S=2^{size_S}$,其中$size_S$为点集$S$的极大生成子图内的边数。特殊的,$f_{o}=g_{o}=0$。

      定义集合幂级数的乘法为子集卷积,考虑集合幂级数$h$和$g$的关系,我们可以得到

        $$h=1+sum_{k geq 1}frac{g^k}{k!}=1+e^h$$

      因此可得

        $$g=ln{(1+h)}$$

      我们再记$f_S$为点集$S$的生成子图的价值和,可得到

        $$f=1+sum{k geq 1}frac{g^k}{k!}k!=frac{1}{1-g}$$

      计算集合幂级数的对数和逆时,因为我们将乘法定义为子集卷积,所以可以将其映射成集合占位幂级数$f_{|S|,S}$后,在将每个集合对应的位看作形式幂级数再暴力求解。

      代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #define mod 998244353
    #define Mod1(x) (x>=mod?x-mod:x)
    #define Mod2(x) (x<0?x+mod:x)
    #define ll long long
    inline ll read()
    {
        ll x=0; char c=getchar(),f=1;
        for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
        for(;'0'<=c&&c<='9';c=getchar())x=x*10+c-'0';
        return x*f;
    }
    inline void write(ll x)
    {
        static int buf[20],len; len=0;
        if(x<0)x=-x,putchar('-');
        for(;x;x/=10)buf[len++]=x%10;
        if(!len)putchar('0');
        else while(len)putchar(buf[--len]+'0');
    }
    inline void writeln(ll x){write(x); putchar('
    ');}
    inline void writesp(ll x){write(x); putchar(' ');}
    int f[25][(1<<20)+5],g[25][(1<<20)+5];
    int cnt[(1<<20)+5],inv[25];
    int x[410],y[410];
    int n,m;
    inline ll power(ll a,ll b)
    {
        ll ans=1;
        for(;b;b>>=1,a=a*a%mod)
            if(b&1)ans=ans*a%mod;
        return ans;
    }
    inline void fwt(int* a,int n)
    {
        for(int i=1;i<n;i<<=1)
            for(int j=0;j<n;j+=(i<<1))
                for(int k=j;k<j+i;k++)
                    a[k+i]=Mod1(a[k+i]+a[k]);
    }
    inline void ifwt(int* a,int n)
    {
        for(int i=1;i<n;i<<=1)
            for(int j=0;j<n;j+=(i<<1))
                for(int k=j;k<j+i;k++)
                    a[k+i]=Mod2(a[k+i]-a[k]);
    }
    int main()
    {
        n=read(); m=read();
        for(int i=0;i<m;i++)
            x[i]=read()-1,y[i]=read()-1;
        for(int i=1;i<1<<n;i++)
            cnt[i]=cnt[i>>1]+(i&1);
        for(int i=1;i<1<<n;i++){
            int tot=0;
            for(int j=0;j<m;j++)
                if((i&(1<<x[j]))&&(i&(1<<y[j])))++tot;
            f[cnt[i]][i]=power(2,tot);
        }
        for(int i=1;i<=n;i++)
            fwt(f[i],1<<n);
        for(int i=1;i<=n;i++)
            inv[i]=power(i,mod-2);
        for(int i=1;i<=n;i++){\求ln
            for(int k=0;k<i;k++)
                for(int j=0;j<1<<n;j++)
                    g[i][j]=(g[i][j]+(ll)k*g[k][j]%mod*f[i-k][j])%mod;
            for(int j=0;j<1<<n;j++)
                g[i][j]=(f[i][j]+(ll)(mod-inv[i])*g[i][j])%mod;
        }
        memset(f,0,sizeof(f));
        for(int i=0;i<1<<n;i++)
            f[0][i]=1;
        for(int i=1;i<=n;i++)\求逆
            for(int k=0;k<i;k++)
                for(int j=0;j<1<<n;j++)
                    f[i][j]=(f[i][j]+(ll)f[k][j]*g[i-k][j])%mod;
        ifwt(f[n],1<<n);
        writeln(f[n][(1<<n)-1]);
        return 0;
    }
    uoj94
  • 相关阅读:
    net core 接入 Google Authenticator
    centos7 安装Mysql8.0笔记
    学习笔记: AOP面向切面编程和C#多种实现
    Exceptionless 生产部署笔记
    图片上下左右自适应对齐
    rem
    mysql command line client 使用命令
    文字溢出换行或者省略号
    一个自欺欺人的代码(便于理解函数和对象基础)
    this、new、模式工厂、创建新的构造函数
  • 原文地址:https://www.cnblogs.com/quzhizhou/p/11311381.html
Copyright © 2011-2022 走看看