题目传送门

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. groovy-2.4.11.jar时出错; invalid LOC header (bad signature)

    Information:java: Errors occurred while compiling module 'security'Information:javac 1.8.0_131 was u ...

  2. C#第一个程序Helloworld

  3. Oracle dmp文件(表)导入与导出

    dmp文件是作为oracle导入和导出表使用的文件格式dmp文件导出dmp文件导出用的比较多的一般是三种,他们分别是:1.导出整个数据库实例下的所有数据2.导出指定用户的所有表3.导出指定表. 打开命 ...

  4. 2019 年百度之星—初赛一 B题 Game

    题目链接 题意:最开始可以选择任意位置,在一个坐标轴上,依次走到一个区间里面,可以选择走一步两步,求最小步数. 思路:贪心,刚开始合并区间,确定初始位置以及方向.往右走肯定到左端点,往左走先到右端点, ...

  5. [CSP-S模拟测试]:周(week)(搜索)

    题目描述 退役之后,$liu\_runda$总会想起学$OI$的时候自己怎样被郭神虐爆……$liu\_runda$学文化课的时候想要学$OI$,学$OI$的时候想要学文化课.为了解决矛盾,他决定以周为 ...

  6. mybatis获取数据库自增id

    http://blog.csdn.net/dyllove98/article/details/8866357 http://www.iteye.com/problems/86864 insert标签中 ...

  7. Spring JDBCTemplate 简单使用

    Spring JDBCTemplate applicationContext.xml配置 <?xml version="1.0" encoding="UTF-8&q ...

  8. 使用代理IP、高匿IP、连接失败

    先百度一下,什么是代理IP 我们使用代理IP就是因为某些站点会屏蔽我们的IP,所以我们要动态的更换代理IP. 代理IP: 其中我们首先选择国内的IP,国外的一般都比较慢,其次不要选择如{新疆乌鲁木齐} ...

  9. Gym 100917M Matrix, The

    题目链接: http://codeforces.com/gym/100917/problem/M --------------------------------------------------- ...

  10. jmeter3.0+ant1.10+jenkins实现接口自动化并发送邮件

    有很多关于接口自动化的文章,此篇仅用于记录自己的学习用.使用jmeter3.0+ant1.10+jenkins2.实现接口自动化并发送邮件,本篇是用的编写build文件来实现发送邮件,也可以用jenk ...