Description

定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与
G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 G 中.
现在给定 s 个结点数相同的图 G1...s, 设 S = {G1, G2, . . . , Gs}, 请问 S 有多少个子集的异
或为一个连通图?

Input

第一行为一个整数s, 表图的个数.
接下来每一个二进制串, 第 i 行的二进制串为 gi, 其中 gi 是原图通过以下伪代码转化得
到的. 图的结点从 1 开始编号, 下面设结点数为 n.
Algorithm 1 Print a graph G = (V, E)
for i = 1 to n do
for j = i + 1 to n do
if G contains edge (i, j) then
print 1
else
print 0
end if
end for
end for
 2 ≤ n ≤ 10,1 ≤ s ≤ 60.

Output

输出一行一个整数, 表示方案数

Sample Input

3
1
1
0

Sample Output

4

HINT

Solution

这道题的出处是去年我们省的省队集训。

回想起去年省队集训的时候,非正式选手的我看到这道题和这道题题解时的一脸懵逼。

“为什么是2^全零行个数次方啊?”

“斯特林数是啥子啊?”

“贝尔数又是啥子啊?”

“这题为什么我看了题解还是不知道怎么做啊?”

“为什么标程的代码这么短啊?”

“……”

时隔了整整一年,重新拿到这道题,感慨颇多。

首先,连通的条件并不好算,我们考虑不连通的情况。

我们先枚举一个划分,表示不同的划分里的点一定在不同的连通块,但在同一个划分里的点不一定在同一个连通块。也就是说所有连接两个不同划分的边都必须为0。这个的方案数可以用高斯消元算,答案会等于2^s-基的个数。

然后我们再考虑每种方案都被重复算了多少遍。一个划分集合如果是另一个划分集合的子集的话那么它被重复算的系数是斯特林数,我们可以暴力把这个容斥系数算出来(如果打表打出来会发现其实是阶乘)。

复杂度是贝尔数的第N项*高斯消元的。

代码的确很短。

Code

 #include <cstdio>
#include <bitset>
#include <cstring>
#define R register
typedef long long ll;
char str[];
int s, n, id[][], len;
std::bitset<> b[], t, c[];
int col[];
ll pw[], ans, f[], S[][];
void dfs(R int x, R int cl)
{
if (x > n)
{
R int cnt = , ji = ;
for (R int i = ; i <= n; ++i)
for (R int j = i + ; j <= n; ++j)
if (col[i] != col[j]) t.set(cnt), ++cnt;
else t.reset(cnt), ++cnt;
for (R int i = ; i <= s; ++i)
{
c[i] = b[i] & t;
// for (R int j = 0; j < len; ++j) printf("%d", c[i][j] == 1); puts("");
}
for (R int i = , bs = ; i <= s && bs < len; )
{
if (c[i][bs] == )
{
for (R int j = i + ; j <= s; ++j)
if (c[j][bs])
{
std::swap(c[i], c[j]);
break;
}
}
if (c[i][bs] == ) {++bs; continue;}
++ji;
for (R int j = i + ; j <= s; ++j)
if (c[j][bs])
c[j] ^= c[i];
++i; ++bs;
}
// for (R int i = 1; i <= n; ++i) printf("%d ", col[i]); puts("");
// printf("base %d pw %lld\n", ji, f[cl] * pw[s - ji]);
ans += f[cl] * pw[s - ji];
return ;
}
for (R int i = ; i <= cl; ++i)
{
col[x] = i;
dfs(x + , cl);
}
col[x] = cl + ;
dfs(x + , cl + );
}
int main()
{
scanf("%d", &s);
pw[] = ;
for (R int i = ; i <= s; ++i)
{
scanf("%s", str); pw[i] = pw[i - ] * ;
len = strlen(str);
for (n = ; n <= ; ++n) if (n * (n - ) == len * ) break;
for (R int j = ; j < len; ++j) b[i][j] = (str[j] == '');
}
// for (R int i = 1; i <= s; ++i) {for (R int j = 0; j < len; ++j) printf("%d", b[i][j] == 1); puts("");}
S[][] = ;
for (R int i = ; i <= n; ++i)
{
S[i][] = ;
for (R int j = ; j <= i; ++j)
S[i][j] = S[i - ][j - ] + j * S[i - ][j];
}
f[] = ;
for (R int i = ; i <= n; ++i)
{
for (R int j = i - ; j; --j)
f[i] -= S[i][j] * f[j];
// printf("%lld\n", f[i]);
}
R int cnt = ;
for (R int i = ; i <= n; ++i)
for (R int j = i + ; j <= n; ++j)
id[i][j] = id[j][i] = cnt++;
dfs(, );
printf("%lld\n", ans);
return ;
}
/*
3
111
111
111
*/

【BZOJ4671】 异或图的更多相关文章

  1. bzoj4671: 异或图——斯特林反演

    [BZOJ4671]异或图 - xjr01 - 博客园 考虑先算一些限制少的情况 gi表示把n个点的图,划分成i个连通块的方案数 连通块之间不连通很好处理(怎么处理看下边),但是内部必须连通,就很难办 ...

  2. bzoj4671: 异或图

    bzoj4671: 异或图 Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 ( ...

  3. bzoj4671 异或图(斯特林反演,线性基)

    bzoj4671 异或图(斯特林反演,线性基) 祭奠天国的bzoj. 题解时间 首先考虑类似于容斥的东西. 设 $ f_{ i } $ 为至少有 $ i $ 个连通块的方案数, $ g_{ i } $ ...

  4. BZOJ4671异或图

    题目描述 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 ...

  5. BZOJ4671 异或图(容斥+线性基)

    题意 定义两个结点数相同的图 \(G_1\) 与图 \(G_2\) 的异或为一个新的图 \(G\) ,其中如果 \((u, v)\) 在 \(G_1\) 与 \(G_2\) 中的出现次数之和为 \(1 ...

  6. BZOJ4671 异或图 斯特林反演+线性基

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4671 题解 半年前刚学计数的时候对这道题怀着深深的景仰,现在终于可以来做这道题了. 类似于一般 ...

  7. 【BZOJ4671】异或图(斯特林反演)

    [BZOJ4671]异或图(斯特林反演) 题面 BZOJ Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出 ...

  8. 【XSY2701】异或图 线性基 容斥原理

    题目描述 定义两个图\(G_1\)与\(G_2\)的异或图为一个图\(G\),其中图\(G\)的每条边在\(G_1\)与\(G_2\)中出现次数和为\(1\). 给你\(m\)个图,问你这\(m\)个 ...

  9. BZOJ 4671 异或图 | 线性基 容斥 DFS

    题面 Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中 ...

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

    传送门 题意: 给出\(s,s\leq 60\)张图,每张图都有\(n,n\leq 10\)个点. 现在问有多少个图的子集,满足这些图的边"异或"起来后,这张图为连通图. 思路: ...

随机推荐

  1. 关于vs code文本编辑器的快捷键

    另一篇编辑器Sublime Text下载.使用教程.插件推荐说明.全套快捷键 基础编辑 快捷键 作用 Ctrl+X 剪切 Ctrl+C 复制 Ctrl+Shift+K 删除当前行 Ctrl+Enter ...

  2. Codeforces 1237B. Balanced Tunnel

    传送门 这一题有点意思 首先预处理出 $pos[x]$ 表示编号 $x$ 的车是第几个出隧道的 然后按进入隧道的顺序枚举每辆车 $x$ 考虑有哪些车比 $x$ 晚进入隧道却比 $x$ 早出隧道 显然是 ...

  3. MySQL 存储引擎的类型以及选择

    针对MySQL,数据最终以什么样的形式保存?以及数据保存在硬盘的什么位置? 1.MySQL的存储引擎 MySQL属于数据管理系统(DBMS),其中包括数据库,负责存储数据:还有数据库访问管理的接口系统 ...

  4. 怎样创建并使用 vue 组件 (component) ?

    组件化开发 需要使用到组件, 围绕组件, Vue 提供了一系列功能方法, 这里仅记录组件的 最简单 的使用方法. 1. 通过 Vue.component(tagName, options) 注册一个 ...

  5. 【原创】大数据基础之ETL vs ELT or DataWarehouse vs DataLake

    ETL ETL is an abbreviation of Extract, Transform and Load. In this process, an ETL tool extracts the ...

  6. JS基础_算数运算符

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. JS中数组与对象的遍历方法实例小结

    一.数组的遍历: 首先定义一个数组 1 arr=['snow','bran','king','nightking']; 1.for循环,需要知道数组的长度; 2.foreach,没有返回值,可以不知道 ...

  8. Java: For循环那些事

    title: Java-for循环那些事 toc: true date: 2019-05-21 10:28:44 categories: Java tags: - Tips --- Java for循 ...

  9. 基于Java使用Flink读取CSV文件,针对批处理,多表联合两种方式Table类和Join方法的实现数据处理,再入CSV文件

    Maven依赖 源头 <dependencies> <dependency> <groupId>org.projectlombok</groupId> ...

  10. 【大数据】初识Hadoop

    因为项目日志体量较大,每天有4-7T的日志量,传统的sqlserver已经不能满足,所以现在需要使用到大数据的相关工具进行记录和使用. 虽然公共项目提供了组件和解决方案,但是对于一些名词.概念还是有必 ...