【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 ...
随机推荐
- 洛谷 SPOJ 题解 SP1 【TEST - Life, the Universe, and Everything】
给出一种主函数递归的方法(其实主函数 main() 也是可以递归的) #include <stdio.h> int main() { int a; scanf("%d" ...
- VIP 视频开发板 上位机 测试软件 下载地址,玩转各自分辨率(V201抢先版)
本上位机最高测试帧率 133fps 目前支持分辨率:更多分辨率支持,敬请期待或给我留言VGA:640*4801.3M:1280*10242M:1600*1200786p:1024*768 格式兼容:1 ...
- LeetCode--300. 最长递增子序列
题目:给定一个无序的整数数组,找到其中最长上升子序列的长度. 示例: 输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4 ...
- salt
更新于 3.25 23:16 salt简介 SaltStack是一个服务器基础架构集中化管理平台,具备配置管理.远程执行.监控等功能,基于Python语言实现,结合轻量级消息队列(ZeroMQ)与Py ...
- 4个点让你彻底明白Redis的各项功能
前言 先看一下Redis是一个什么东西.官方简介解释到: Redis是一个基于BSD开源的项目,是一个把结构化的数据放在内存中的一个存储系统,你可以把它作为数据库,缓存和消息中间件来使用.同时支持st ...
- poj 2398 Toy Storage(计算几何)
题目传送门:poj 2398 Toy Storage 题目大意:一个长方形的箱子,里面有一些隔板,每一个隔板都可以纵切这个箱子.隔板将这个箱子分成了一些隔间.向其中扔一些玩具,每个玩具有一个坐标,求有 ...
- 使用between操作符过滤数据
select prod_name,prod_price from products where prod_price between 5 and 10; 就可以查询处5-10之间的所有数据 betwe ...
- [ASP.NET Core 3框架揭秘] 配置[5]:配置数据与数据源的实时同步
在<配置模型总体设计>介绍配置模型核心对象的时候,我们刻意回避了与配置同步相关的API,现在我们利用一个独立文章来专门讨论这个话题.配置的同步涉及到两个方面:第一,对原始的配置源实施监控并 ...
- Educational Codeforces Round 78 (Rated for Div. 2)
A题 给出n对串,求s1,是否为s2一段连续子串的重排,串长度只有100,从第一个字符开始枚举,sort之后比较一遍就可以了: char s1[200],s2[200],s3[200]; int ma ...
- 【GZOI 2019】特技飞行
Problem Description 公元 \(9012\) 年,Z 市的航空基地计划举行一场特技飞行表演.表演的场地可以看作一个二维平面直角坐标系,其中横坐标代表着水平位置,纵坐标代表着飞行高度. ...