zoukankan      html  css  js  c++  java
  • bzoj 4671 异或图 —— 容斥+斯特林反演+线性基

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4671

    首先,考虑容斥,就是设 ( t[i] ) 表示至少有 ( i ) 个连通块的方案数;

    我们希望得到恰好有一个连通块的方案数,但这里不能直接 ( + t[1] - t[2] + t[3] - t[4] ... ),因为每个“恰好 ( i ) 个连通块”的情况并不是在各种 ( t[j] ( j<=i ) ) 中只被算了一次,而是因为标号,被算了 ( S(i,j) ) 次;

    所以希望得到一个容斥系数 ( f[i] ) ,若设 ( g[m] ) 表示恰好 ( m ) 个连通块的情况,则令 ( g[m] = sumlimits_{i=1}^{m} S(m,i) * f[i] * t[i] )

    又因为 ( ans = g[1] ),所以干脆令 ( f[i] ) 满足 ( [m=1] = sumlimits_{i=1}^{m} S(m,i) * f[i] ),代入 ( t[i] ),算出的就是 ( g[1] ) ,即答案;

    可以斯特林反演,于是 ( f[m] = sumlimits_{i=1}^{m} s(m,i) * (-1)^{m-i} * [i=1] ),这里的 ( s(m,i) ) 是第一类斯特林数;

    于是 ( f[m] = (m-1)! * (-1)^{m-1} )

    接下来问题就是求 ( t[i] )

    ( dfs ) 枚举集合划分,复杂度是 ( Bell[n] ) 的,可以接受;

    枚举了集合划分后,这些集合之间一定不能有边,这与每张图的连边情况构成了一组线性方程组;

    找出线性基有 ( cnt ) 个,那么 ( s-cnt ) 张图的使用是不受限制的,换句话说,即使随便使用,构成一种情况,也可以通过线性基的那些图调整成集合间没有连边的情况;

    所以 ( t[集合数] ) 加上 ( 2^{s-cnt} )

    不用数组而用一个 long long 整数,再预处理2的整数次幂,可以把时间优化到bzoj上的一般水平囧。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int s,n,m,cnt,id[15][15],col[15],jc[15],t[50];
    bool sid[65][50],vis[50];
    ll f[15],a[50],bin[65];
    char ch[65];
    ll pw(ll a,int b)
    {
      ll ret=1;
      for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a;
      return ret;
    }
    void add(int x)
    {
      cnt++; a[cnt]=0;
      for(int i=1;i<=s;i++)
        if(sid[i][x])a[cnt]|=bin[i-1];//G[i]->ed[x]
    }
    int cal()
    {
      int num=0;
      memset(vis,0,sizeof vis);
      for(int i=1;i<=cnt;i++)
        for(int j=1;j<=s;j++)
          {
        if(!(bin[j-1]&a[i]))continue;
        if(vis[j])a[i]^=a[t[j]];
        else {num++,vis[j]=1,t[j]=i; break;}//
          }
      return s-num;
    }
    void dfs(int x,int cr)
    {
      if(x==n+1)
        {
          cnt=0;
          for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
          if(col[i]!=col[j])add(id[i][j]);
          f[cr]+=pw(2,cal());
          return;
        }
      for(int i=1;i<=cr;i++)col[x]=i,dfs(x+1,cr),col[x]=0;
      col[x]=cr+1; dfs(x+1,cr+1);
      col[x]=0;
    }
    void init()
    {
      jc[0]=1;
      for(int i=1;i<=n;i++)jc[i]=jc[i-1]*i;
      bin[0]=1;
      for(int i=1;i<=s;i++)bin[i]=bin[i-1]+bin[i-1];
    }
    int main()
    {
      scanf("%d",&s);
      for(int i=1;i<=s;i++)
        {
          scanf("%s",ch+1); m=strlen(ch+1);
          for(int j=1;j<=m;j++)sid[i][j]=ch[j]-'0';
        }
      while(n*(n-1)/2<m)n++;
      for(int i=1,tmp=0;i<=n;i++)
        for(int j=i+1;j<=n;j++)id[i][j]=id[j][i]=++tmp;//id[j][i]
      init();
      dfs(1,0);
      ll ans=0;
      for(int i=1;i<=n;i++)
        ans+=(i&1?1:-1)*jc[i-1]*f[i];
      printf("%lld
    ",ans);
      return 0;
    }
  • 相关阅读:
    spark编译
    使用MapReduce实现两个文件的Join操作
    响应式 Web 设计
    响应式 Web 设计
    900W+数据只用300ms搞定!SQL查询优化这样做最快耗时347ms
    响应式 Web 设计
    CSS3 多媒体查询实例
    CSS3 多媒体查询:查找设备的类型,CSS3 根据设置自适应显示
    CSS3 弹性盒子(Flex Box):确保元素拥有恰当的行为的布局方式
    CSS3 框大小:padding(内边距) 和 border(边框)
  • 原文地址:https://www.cnblogs.com/Zinn/p/10072542.html
Copyright © 2011-2022 走看看