【BZOJ4671】 异或图
Description
Input
Output
Sample Input
1
1
0
Sample Output
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】 异或图的更多相关文章
- bzoj4671: 异或图——斯特林反演
[BZOJ4671]异或图 - xjr01 - 博客园 考虑先算一些限制少的情况 gi表示把n个点的图,划分成i个连通块的方案数 连通块之间不连通很好处理(怎么处理看下边),但是内部必须连通,就很难办 ...
- bzoj4671: 异或图
bzoj4671: 异或图 Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 ( ...
- bzoj4671 异或图(斯特林反演,线性基)
bzoj4671 异或图(斯特林反演,线性基) 祭奠天国的bzoj. 题解时间 首先考虑类似于容斥的东西. 设 $ f_{ i } $ 为至少有 $ i $ 个连通块的方案数, $ g_{ i } $ ...
- BZOJ4671异或图
题目描述 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中, 否则这条边不在 ...
- BZOJ4671 异或图(容斥+线性基)
题意 定义两个结点数相同的图 \(G_1\) 与图 \(G_2\) 的异或为一个新的图 \(G\) ,其中如果 \((u, v)\) 在 \(G_1\) 与 \(G_2\) 中的出现次数之和为 \(1 ...
- BZOJ4671 异或图 斯特林反演+线性基
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4671 题解 半年前刚学计数的时候对这道题怀着深深的景仰,现在终于可以来做这道题了. 类似于一般 ...
- 【BZOJ4671】异或图(斯特林反演)
[BZOJ4671]异或图(斯特林反演) 题面 BZOJ Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出 ...
- 【XSY2701】异或图 线性基 容斥原理
题目描述 定义两个图\(G_1\)与\(G_2\)的异或图为一个图\(G\),其中图\(G\)的每条边在\(G_1\)与\(G_2\)中出现次数和为\(1\). 给你\(m\)个图,问你这\(m\)个 ...
- BZOJ 4671 异或图 | 线性基 容斥 DFS
题面 Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 (u, v) 在 G 中 ...
- 【bzoj4671】异或图(容斥+斯特林反演+线性基)
传送门 题意: 给出\(s,s\leq 60\)张图,每张图都有\(n,n\leq 10\)个点. 现在问有多少个图的子集,满足这些图的边"异或"起来后,这张图为连通图. 思路: ...
随机推荐
- 怎样安装 cnpm 并切换到淘宝镜像?
如果不使用 vpn , 在国内直接使用 npm 的官方镜像会很慢,这里推荐使用淘宝 NPM 镜像.淘宝 NPM 镜像是一个完整的 npmjs.org 镜像,可以用此代替官方版本(只读). 操作方法如下 ...
- application.properties参数详解
# ----------------------------------------# CORE PROPERTIES# --------------------------------------- ...
- ModbusRtu通信报文详解【二】
这里接着上一篇内容对ModbusRtu的通信报文做个详细描述: [1]强制单个线圈 功能码:05H [2]预置单个寄存器 功能码:06H [3]强制多个线圈 功能码;0FH [4]预置多个寄存器 功能 ...
- 【weixin】微信h5支付
一.使用场景 H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付. 主要用于触屏版的手机浏览器请求微信支付的场景.可以方便 ...
- ReadWriteLock读写之间互斥吗
开发中遇到并发的问题一般会用到锁,Synchronized存在明显的一个性能问题就是读与读之间互斥:ReadWriteLock是JDK5中提供的读写分离锁.读写分离锁可以有效地帮助减少锁竞争,以提升系 ...
- ubuntu系统新用户添加
大概是4个步骤吧,是用脚本实现的,这里我列一下关键点 sudo useradd -m userYouWantAdd sudo passwd userYouWantAdd sudo usermod -a ...
- C# 基础 字符串 集合 文件操作
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 【死磕 Java 集合】— ConcurrentSkipListMap源码分析
转自:http://cmsblogs.com/?p=4773 [隐藏目录] 前情提要 简介 存储结构 源码分析 主要内部类 构造方法 添加元素 添加元素举例 删除元素 删除元素举例 查找元素 查找元素 ...
- [转] - Linux中使用alternatives切换Jdk版本
1. 准备JDK包,分别是1.7和1.8,jdk-7u79-linux-x64.tar.gz和jdk-8u161-linux-x64.gz: 2. 解压,解压后的目录结构如图所示: JDK1.7: J ...
- DA_06_高级文本处理命令
Linux中没有盘符这个概念,只有一个根目录“/”,所有文件都在它下面:点击计算机,下面存放的都是根目录下的东西: 2.6 文本文件编辑命令 1.cat 命令用于查看纯文本文件(内容较少的:一次性全部 ...