题目传送门

https://lydsy.com/JudgeOnline/problem.php?id=4671

题解

半年前刚学计数的时候对这道题怀着深深的景仰,现在终于可以来做这道题了。

类似于一般的容斥和反演题,我们发现整个图是联通的图非常不好求。于是我们转化为整个图钦定了有 \(i\) 个块必须不连通,其余任意的方案数。

然后考虑这个怎么求,我们可以暴力枚举一下把这些数分成很多组,显然方案数就时 \(B_n\)(贝尔数,就是 \(\sum\limits_{i=0}^n \begin{Bmatrix}n\\i\end{Bmatrix}\) 的和,在 \(n \leq 10\) 的时候都不超过十万级别)。

然后就是相当于有一些边不能存在,其余的别可以任意存在。考虑用一个线性基来维护。由于边数不超过 \(\frac{n(n-1)}2\),所以可以用 ll 表示。然后问题转化为一个数有多少个子集存在于线性基中。

但是一个数有多少个子集存在于线性基中不太好维护,经过某位同学的提示,可以想到把那些可以任意为 \(0/1\) 的位扔掉,只记录只能为 \(0\) 的位,把这些位扔进线性基。最后只需要用线性基求出有多少种方案使得异或和为 \(0\) 就可以了。


以下是代码,时间复杂度为 \(O(B_nn^2m)\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
template<typename I>
inline void read2(char *s, I &x) {
int f = 0, c;
while (!isdigit(c = *s++)) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = *s++)) x = (x << 1) + (c & 15);
f ? x = -x : 0;
} const int N = 45 + 7;
const int M = 60 + 7; int n, m, sn, ssn;
int a[N], bl[N], ss[N];
ll b[M], f[N], S[N][N];
pii dy[N];
char s[N], p[N]; struct XXJ {
ll a[N];
inline void cls() { memset(a, 0, sizeof(a)); }
inline bool ins(ll x) {
for (int i = ssn - 1; ~i; --i)
if ((x >> i) & 1) {
if (a[i]) x ^= a[i];
else return a[i] = x, 1;
}
return 0;
}
inline int count() {
int cnt = 0;
for (int i = ssn - 1; ~i; --i) if (a[i]) ++cnt;
return cnt;
}
} gg; inline void calc(int y) {
ss[0] = 0;
for (int i = 0; i < sn; ++i)
if (bl[dy[i].fi] != bl[dy[i].se]) ss[++ss[0]] = i;
ssn = ss[0], gg.cls();
for (int i = 1; i <= m; ++i) {
ll c = 0;
for (int j = ss[0]; j; --j) c = c << 1 | ((b[i] >> ss[j]) & 1);
gg.ins(c);
}
f[y] += 1ll << (m - gg.count());
} inline void dfs(int x, int y) {
if (x == n + 1) return calc(y);
for (int i = 1; i <= y + 1; ++i) bl[x] = i, dfs(x + 1, std::max(y, i));
} inline void work() {
dfs(1, 0);
ll ans = 0;
S[0][0] = 1;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= i; ++j) S[i][j] = S[i - 1][j - 1] + (i - 1) * S[i - 1][j];
for (int i = 1; i <= n; ++i)
if ((i - 1) & 1) ans -= S[i][1] * f[i];
else ans += S[i][1] * f[i];
printf("%lld\n", ans);
} inline void init() {
read(m);
for (int i = 1; i <= m; ++i) {
scanf("%s", s + 1);
int nn = strlen(s + 1);
std::reverse(s + 1, s + nn + 1);
n = (1 + (int)sqrt(1 + 8 * nn)) >> 1;
read2(s + 1, b[i]);
}
sn = 0;
for (int i = 1; i <= n; ++i)
for (int j = i + 1; j <= n; ++j) dy[sn++] = pii(i, j);
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

BZOJ4671 异或图 斯特林反演+线性基的更多相关文章

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

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

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

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

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

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

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

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

  5. bzoj 4671 异或图——容斥+斯特林反演+线性基

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4671 考虑计算不是连通图的方案,乘上容斥系数来进行容斥. 可以枚举子集划分(复杂度是O(Be ...

  6. bzoj 4671 异或图 —— 容斥+斯特林反演+线性基

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4671 首先,考虑容斥,就是设 \( t[i] \) 表示至少有 \( i \) 个连通块的方 ...

  7. bzoj4671: 异或图

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

  8. BZOJ4671异或图

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

  9. P5169 xtq的异或和(FWT+线性基)

    传送门 我咋感觉我学啥都是白学-- 首先可以参考一下这一题,从中我们可以知道只要知道两点间任意一条路径以及整个图里所有环的线性基,就可以得知这两个点之间的所有路径的异或和 然而我好像并不会求线性基能张 ...

随机推荐

  1. php in_array()函数 语法

    php in_array()函数 语法 作用:搜索数组中是否存在指定的值.大理石机械构件价格 语法:in_array(search,array,type) 参数: 参数 描述 search 必需.规定 ...

  2. GoldenGate—日常管理

    Classic Replicat Mode (一)源端和目标端新增加复制表 根据需求将生产库中PROCESS_LOG表通过ogg同步到测试库中:操作步骤: 当GoldenGate仅打开DML复制时,源 ...

  3. django中的url控制

    1.django中的第一个控件:url控制  (路由分发) urls.py:请求路径与视图函数的之间的关系 步骤: 1.首先是要配置环境,   2.其次就是引路径   3.在视图的文件夹里面写相应的函 ...

  4. Linux学习篇(四)-Linux 文件管理命令详解

    rootfs:根文件系统,Root FileSystem 的简称. Linux 文件命名规则 长度不超过255个字符. 不能使用/当文件名. 严格区分大小写. Linux 目录简介 / 根目录 /bo ...

  5. day46----JavaScript的函数及对象小结

    一:函数 01:普通函数 function f1(){ console.log("Helleo world") } f1(); //调用函数 -->Helleo world ...

  6. day17—Flex弹性布局详解(一)

    转行学开发,代码100天——2018-04-02 今天看到一篇大神的文章,关于flex布局的详解,对flex用法介绍的相当详细,非常有助于我等初学者更深入了解这种布局方式. 文章链接 [基础知识]Fl ...

  7. 第1 章 mysql数据库之简单的DDL和DML sql语句

    一.SQL 介绍 1.什么是sql? SQL,英文全称(Structured Query Language),中文是结构化查询语言,它是一种对关系数据库中数据进行定义和操作的语言方法,是大多数关系数据 ...

  8. python实现自动发送邮件

    Python发送邮件成功的前提,应是先开启授权码.目前使用广泛的邮箱有:163邮箱.qq邮箱等. 163邮箱开启授权码的方法如下图: qq邮箱开启授权码的方法如下图: 接下来代码的实现: import ...

  9. 关于狗书《Flask web开发 基于python的Web开发应用实战》中加入用户隐私功能

    目前是第二次撸狗书,在用户页面这一块我个人觉得有些问题(基于交互设计).按理来说,我作为一个权限只有User的个人用户来说,肯定不喜欢让别人看到我的真实姓名,地址之类的敏感信息.所以我应该是可以设置成 ...

  10. 【报错】Validation failed for object='userLogin'. Error count: 1

    提交表单之后: Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing ...