【bzoj4671】异或图(容斥+斯特林反演+线性基)
题意:
给出\(s,s\leq 60\)张图,每张图都有\(n,n\leq 10\)个点。
现在问有多少个图的子集,满足这些图的边“异或”起来后,这张图为连通图。
思路:
直接考虑判断图的连通不好判断,所以考虑枚举连通块来进行容斥。
定义\(f_i\)表示有\(i\)个连通块的答案,发现连通块这个东西也不好处理,我们只能处理出有多少个连通块,但无法确定每个连通块内部的连通关系。
定义\(g_i\)为至少有\(i\)个连通块的方案数,那么就有关系式:\(\displaystyle g_i=\sum_{j=i}^n \begin{Bmatrix}
j \\ i
\end{Bmatrix}f_j\)。至于为什么要乘以一个第二类斯特林数,相当于我们将单个的连通块再进行组合,有不同的组合方式。此时\(g_i\)就相当于有\(i\)个连通块,内部可连通可不连通的方案数。
因为最终所求为\(f_1\),通过斯特林反演可得:\(\displaystyle f_1=\sum_{i=1}^n(-1)^{i-1}\begin{bmatrix}
i \\ 1
\end{bmatrix}g_i\)。那么现在只需要算\(g_i\)即可。因为点数很少,可以直接枚举子集划分,我们只需要保证最后不同的集合之间没有边相连即可。
当确定了一种子集划分过后,将连接不同集合的边拿出来,将每张图这类边转为二进制插入线性基中,最后的基为\(c\)个,那么答案就为\(2^{s-c}\)。
将答案累加入\(f_i\)即可。
这个题大概就这样做完了,但还有一些小细节,其中,斯特林反演的时候和常见形式稍有不同,但可以通过反转公式证明:
\begin{aligned}
&\sum_{k=m}^n(-1)^{n-k}\begin{bmatrix}
n \\ k
\end{bmatrix}\begin{Bmatrix}
k \\ m
\end{Bmatrix}=[n=m]\\
&\sum_{k=m}^n(-1)^{k-m}\begin{Bmatrix}
n \\ k
\end{Bmatrix}\begin{bmatrix}
k \\ m
\end{bmatrix}=[n=m]
\end{aligned}
\right.
\]
最后的答案为\(2^{s-c}\)的原因在于,我们相当于来求若干个数异或起来为\(0\)的方案数,每个图用\(x_i\)来表示其最终状态,那么如果有\(c\)个基,说明就有\(s-c\)个自由变量,对于任意一组自由变量的取值,我们都能找到一组唯一的对应的解满足方程。
其实这个本质上就是求解一个异或方程组。
代码如下:
/*
* Author: heyuhhh
* Created Time: 2019/12/17 15:36:21
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << '\n'; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
#define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 105;
int s, n;
char ch[N];
int G[N][N][N];
int a[N];
ll p[64], fac[N];
ll ans;
void dfs(int x, int up) {
if(x == n) {
memset(p, 0, sizeof(p));
int c = 0;
for(int k = 1; k <= s; k++) {
ll res = 0;
int tot = 0;
for(int i = 1; i <= n; i++) {
for(int j = i + 1; j <= n; j++) {
if(a[i] != a[j]) res |= ((ll)G[k][i][j] << tot);
++tot;
}
}
for(int i = tot; i >= 0; i--) if(res >> i & 1) {
if(!p[i]) {
++c; p[i] = res;
break;
}
res ^= p[i];
}
}
if(up & 1) ans += fac[up - 1] * (1ll << (s - c));
else ans -= fac[up - 1] * (1ll << (s - c));
return;
}
for(int i = 1; i <= up + 1; i++) {
a[x + 1] = i; dfs(x + 1, max(i, up));
}
}
void run(){
fac[0] = 1;
for(int i = 1; i < 12; i++) fac[i] = fac[i - 1] * i;
for(int k = 1; k <= s; k++) {
cin >> (ch + 1);
int len = strlen(ch + 1), cnt = 0;
for(int j = 1; !n; j++) if(j * (j - 1) == 2 * len) n = j;
for(int i = 1; i <= n; i++) {
for(int j = i + 1; j <= n; j++) {
G[k][i][j] = ch[++cnt] - '0';
}
}
}
a[1] = 1;
dfs(1, 1);
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
while(cin >> s) run();
return 0;
}
【bzoj4671】异或图(容斥+斯特林反演+线性基)的更多相关文章
- bzoj 4671 异或图——容斥+斯特林反演+线性基
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4671 考虑计算不是连通图的方案,乘上容斥系数来进行容斥. 可以枚举子集划分(复杂度是O(Be ...
- bzoj 4671 异或图 —— 容斥+斯特林反演+线性基
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4671 首先,考虑容斥,就是设 \( t[i] \) 表示至少有 \( i \) 个连通块的方 ...
- 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. 题解时间 首先考虑类似于容斥的东西. 设 $ f_{ i } $ 为至少有 $ i $ 个连通块的方案数, $ g_{ i } $ ...
- bzoj4671: 异或图——斯特林反演
[BZOJ4671]异或图 - xjr01 - 博客园 考虑先算一些限制少的情况 gi表示把n个点的图,划分成i个连通块的方案数 连通块之间不连通很好处理(怎么处理看下边),但是内部必须连通,就很难办 ...
- bzoj4671: 异或图
bzoj4671: 异或图 Description 定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G, 其中如果 (u, v) 在 G1 与 G2 中的出现次数之和为 1, 那么边 ( ...
- HDU 2841 容斥 或 反演
$n,m <= 1e5$ ,$i<=n$,$j<=m$,求$(i⊥j)$对数 /** @Date : 2017-09-26 23:01:05 * @FileName: HDU 284 ...
- 【题解】[HAOI2018]染色(NTT+容斥/二项式反演)
[题解][HAOI2018]染色(NTT+容斥/二项式反演) 可以直接写出式子: \[ f(x)={m \choose x}n!{(\dfrac 1 {(Sx)!})}^x(m-x)^{n-Sx}\d ...
随机推荐
- 最全的linux系统安装教程和排错方法
第4章 linux信息和系统安装与连接 260 4.1 linux的发展历史 260 4.2 GPL协议,FSF协议 261 4.3 linux系统的安装 261 4.3.1 ...
- Robotframework常见问题收集
一.Robotframework1.7.3控制台乱码处理 1.找到文件C:\Python37\Lib\site-packages\robotide\contrib\testrunner\testrun ...
- Java_输入整数求阶乘
import java.util.Scanner;public class Work4{ public static void main(String[] args){ // 创建Scanner对象 ...
- MYSQL-JDBC批量新增-更新-删除
目录 1 概述 2 开启MYSQL服务端日志 3 深入MYSQL/JDBC批量插入 3.1 从一个例子出发 3.2 JDBC的批量插入操作 3.3 两个常被忽略的问题 3.5 误区 4 MYSQL/J ...
- CCF-CSP题解 201803-3 URL映射
题目要求写一个简易的URL规则和URL地址匹配的程序. 说说我的思路. 将URL规则和地址都截成片段用结构体\(<type, str[]>\)存储.对于URL规则,\(type\)为0代表 ...
- poj 2513 Colored Sticks (trie树+并查集+欧拉路)
Colored Sticks Time Limit: 5000MS Memory Limit: 128000K Total Submissions: 40043 Accepted: 10406 ...
- hdu 1028 Ignatius and the Princess III (n的划分)
Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ...
- 记录一次Windows简单构建Dockerfile
参考文档[https://www.cnblogs.com/GraceSkyer/p/9908984.html] 1]环境说明 操作系统 :win10 ,docker软件:Docker for Win ...
- c++-内联函数和函数重载和默认参数和函数指针
内联函数 C++ 内联函数是通常与类一起使用.如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方. 对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编 ...
- leaflet-webpack 入门开发系列六矢量瓦片(附源码下载)
前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...