题意
定义两个结点数相同的图 G1 与图 G2 的异或为一个新的图 G ,其中如果 (u,v) 在 G1 与 G2 中的出现次数之和为 1 , 那么边 (u,v) 在 G 中, 否则这条边不在 G 中.
现在给定 s 个结点数相同的图 G1...s , 设 S=G1,G2,⋯,Gs , 请问 S 有多少个子集的异或为一个连通图?
n≤10,s≤60
题解
原来听过这题,但一直没有想去写,又讲了一遍,就来做了下,可是还不会。。。
连通图计数的一个经典思路就是容斥。
对于这道题,我们先用贝尔数 bell(n) 的时间来枚举 n 个点的子集(联通块)划分,强制连通性 至少 是这个划分。
也就是说,不同子集的两个点之间一定没有边,相同子集的两个点则任意。
对于一个有 m 个连通块的图。令 fi 为至少有 i 个联通块的容斥系数需要满足
m∑i=1{mi}fi=[m=1]
可以斯特林反演,也可以打表找规律得出
fi=(−1)i−1(i−1)!
那么问题就转化成,我们只考虑不同子集中的边。对于 s 个边集,有多少种异或方案使得异或和为 0 。
这个显然是可以利用线性基得到异或方案的,记线性基的元素个数为 tot ,由于之中的元素是线性无关的,其他的 2s−tot 个集合是一定可以通过异或(或不异或)线性基里的某些元素得到 0 的。
那么方案数其实就是 2s−tot 。
因为此题卡常,所以要卡一些常数才能通过此题qwq 具体可以看代码实现优化。
代码
#include <bits/stdc++.h>
#define For(i, l, r) for (register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for (register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Rep(i, r) for (register int i = (0), i##end = (int)(r); i < i##end; ++i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
using namespace std;
template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }
inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
}
void File() {
#ifdef zjp_shadow
freopen ("4671.in", "r", stdin);
freopen ("4671.out", "w", stdout);
#endif
}
typedef long long ll;
const int N = 12, M = 62;
int Strl[N][N], id[N][N], n, s, fac[N], coef[N];
bitset<N> E[M][N]; char str[M];
ll base[M], ans; int bel[N];
pair<int, int> ins[M];
void Dfs(int u, int tot) {
if (u > n) {
Set(base, 0);
int res = 0, tmp = -1;
For (i, 1, n) For (j, i + 1, n)
if (bel[i] != bel[j]) {
ins[++ tmp] = make_pair(i, j);
}
For (i, 1, s) {
ll now = 0;
For (j, 0, tmp) if (E[i][ins[j].first][ins[j].second]) now |= 1ll << j;
Fordown (j, tmp, 0) if (now >> j & 1) {
if (base[j]) now ^= base[j];
else { base[j] = now; ++ res; break; }
}
}
ans += coef[tot] * (1ll << (s - res));
return;
}
For (i, 1, tot + 1)
bel[u] = i, Dfs(u + 1, max(tot, i));
}
int main () {
File();
s = read();
scanf ("%s", str + 1);
int len = strlen(str + 1);
while (n * (n - 1) / 2 < len) ++ n;
For (k, 1, s) {
len = 0;
For (i, 1, n) For (j, i + 1, n)
E[k][i][j] = str[id[i][j] = ++ len] - '0';
if (k < s) scanf ("%s", str + 1);
}
fac[0] = 1;
For (i, 1, n) {
fac[i] = 1ll * fac[i - 1] * i;
coef[i] = (i & 1 ? 1 : -1) * fac[i - 1];
}
Dfs(1, 0);
printf ("%lld\n", ans);
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】