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] = \sum\limits_{i=1}^{m} S(m,i) * f[i] * t[i] \)

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

可以斯特林反演,于是 \( f[m] = \sum\limits_{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\n",ans);
  return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/10072542.html

时间: 2024-07-30 12:53:21

bzoj 4671 异或图 —— 容斥+斯特林反演+线性基的相关文章

【bzoj4671】异或图(容斥+斯特林反演+线性基)

传送门 题意: 给出\(s,s\leq 60\)张图,每张图都有\(n,n\leq 10\)个点. 现在问有多少个图的子集,满足这些图的边"异或"起来后,这张图为连通图. 思路: 直接考虑判断图的连通不好判断,所以考虑枚举连通块来进行容斥. 定义\(f_i\)表示有\(i\)个连通块的答案,发现连通块这个东西也不好处理,我们只能处理出有多少个连通块,但无法确定每个连通块内部的连通关系. 定义\(g_i\)为至少有\(i\)个连通块的方案数,那么就有关系式:\(\displaystyle

bzoj 4671: 异或图

4671: 异或图 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 61  Solved: 39[Submit][Status][Discuss] Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 G 中. 现在给定 s 个结点数相同的图 G1...s, 设 S = {G1, G2, .

[BZOJ 3129] [Sdoi2013] 方程 【容斥+组合数取模+中国剩余定理】

题目链接:BZOJ - 3129 题目分析 使用隔板法的思想,如果没有任何限制条件,那么方案数就是 C(m - 1, n - 1). 如果有一个限制条件是 xi >= Ai ,那么我们就可以将 m 减去 Ai - 1 ,相当于将这一部分固定分给 xi,就转化为无限制的情况了. 如果有一些限制条件是 xi <= Ai 呢?直接来求就不行了,但是注意到这样的限制不超过 8 个,我们可以使用容斥原理来求. 考虑容斥:考虑哪些限制条件被违反了,也就是说,有哪些限制为 xi <= Ai 却是 xi

[BZOJ 3198] [Sdoi2013] spring 【容斥 + Hash】

题目链接:BZOJ - 3198 题目分析 题目要求求出有多少对泉有恰好 k 个值相等. 我们用容斥来做. 枚举 2^6 种状态,某一位是 1 表示这一位相同,那么假设 1 的个数为 x . 答案就是 sigma((-1)^(x - k) * AnsNow * C(x, k)) .注意 x 要大于等于 k. 对于一种状态,比如 10110,就是要保证第 1, 3, 4 个值相同. 这些值相同的对数怎么来求呢?使用Hash. 将这些位上的值 Hash 成一个数,然后枚举  [1, i] , 每次求

BZOJ 2005 [Noi2010]能量采集 (容斥)

[Noi2010]能量采集 Time Limit: 10 Sec  Memory Limit: 552 MB Submit: 2324  Solved: 1387 [Submit][Status][Discuss] Description 栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量.在这些植物采集能量后,栋栋再使用一个能量汇集机器把这些植物采集到的能量汇集到一起. 栋栋的植物种得非常整齐,一共有n列,每列有m棵,植物的横竖间距都一样,因此对于每一棵植物,栋栋可以

【BZOJ 4455】 [Zjoi2016]小星星 容斥计数

dalao教导我们,看到计数想容斥……卡常策略:枚举顺序.除去无效状态.(树结构) #include <cstdio> #include <cstring> #include <algorithm> typedef long long LL; const int N=20; LL f[N][N]; int n,m,d[N][N],full; bool yeah[N]; int st[N],cnt; struct V{ int to,next; }c[N<<1

bzoj 4036 按位或 —— min-max容斥+FMT

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4036 min-max容斥:https://blog.csdn.net/ez_2016gdgzoi471/article/details/81416333 二项式反演:https://blog.csdn.net/ez_2016gdgzoi471/article/details/81408416 而出现 \( S \) 的期望,就是 \( S \) 每一位出现的期望中的最大值: 所以 \( E

【二分+容斥+莫比乌斯反演】BZOJ2440 完全平方数

Description 求第k个没有完全平方因子的数,k<=1e9. Solution 这其实就是要求第k个µ[i](莫比乌斯函数)不为0的数. 然而k太大数组开不下来是吧,于是这么处理. 二分答案x,问题转化为求[1,x]间有多少个没有完全平方因子的数. 容斥,加上全部,减去一个质数的平方的倍数个数,加上两个质数乘积的平方的倍数个数... 然后发现,每个数的系数就是µ 这也说明了莫比乌斯的原理就是容斥,µ函数就是容斥系数 具体来说,对于每一个i<=sqrt(x),对于ans的贡献就是µ[i]

cf900D. Unusual Sequences(容斥 莫比乌斯反演)

题意 题目链接 Sol 首先若y % x不为0则答案为0 否则,问题可以转化为,有多少个数列满足和为y/x,且整个序列的gcd=1 考虑容斥,设\(g[i]\)表示满足和为\(i\)的序列的方案数,显然\(g[i] = 2^{i-1}\)(插板后每空位放不放) 同时还可以枚举一下gcd,设\(f[i]\)表示满足和为\(i\)且所有数的gcd为1的方案,\(g[i] = \sum_{d | i} f[\frac{n}{d}]\) 反演一下,\(f[i] = \sum_{d | i} \mu(d)