Description:
定義兩個結點數相同的圖 與圖 的異或爲一個新的圖 , 其中如果 在 與
中的出現次數之和爲 , 那麼邊 在 中, 否則這條邊不在 中.
現在給定 個結點數相同的圖 , 設 , 請問 有多少個子集的異
或爲一個連通圖?
Solution:
直接枚舉不可做,那麼考慮容斥,計算至少有幾個連通塊進行容斥,設方案數爲 。那麼結果就是恰好有i個連通塊,那麼就是 。
那麼花費 的時間劃分子集,這些子集之間不能有邊,利用線性基算出自由元數量 ,那麼對應的方案數就是 。
考慮 和 的關係,有
根據斯特林反演
那麼得出
所以每次計算出 ,然後套入式子即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 11, maxm = 65;
int n, m;
long long ans;
int g[maxm][maxn][maxn], bl[maxn];
long long a[maxm], fac[maxn];
char s[maxm];
void dfs(int dep, int k) {
if(dep == n) {
memset(a, 0, sizeof(a));
for(int i = 1; i <= n; ++i) {
for(int j = i + 1; j <= n; ++j) {
if(bl[i] != bl[j]) {
long long tmp = 0;
for(int u = 1; u <= m; ++u) {
tmp |= 1LL * g[u][i][j] << (u - 1);
}
for(int t = m - 1; ~t; --t) {
if(tmp >> t & 1) {
if(a[t]) {
tmp ^= a[t];
} else {
a[t] = tmp;
break;
}
}
}
}
}
}
int c = 0;
for(int i = 0; i < m; ++i) {
c += a[i] > 0;
}
ans += ((k & 1) ? 1 : -1) * (1LL << (m - c)) * fac[k - 1];
return;
}
for(int i = 1; i <= k + 1; ++i) {
bl[dep + 1] = i;
dfs(dep + 1, max(k, i));
}
}
int main() {
scanf("%d", &m);
for(int i = 1; i <= m; ++i) {
scanf("%s", s + 1);
int l = strlen(s + 1), t = 0;
n = (1 + sqrt(1 + (l << 3))) / 2;
for(int u = 1; u <= n; ++u) {
for(int v = u + 1; v <= n; ++v) {
g[i][u][v] = s[++t] - '0';
}
}
}
fac[0] = 1;
for(int i = 1; i <= n; ++i) {
fac[i] = fac[i - 1] * i;
}
dfs(0, 0);
printf("%lld\n", ans);
return 0;
}