zoukankan      html  css  js  c++  java
  • [BZOJ 4671]异或图

    Description

    题库链接

    给定 (s) 个结点数相同且为 (n) 的图 (G_1sim G_s) ,设 (S = {G_1, G_2,cdots , G_s}) ,问 (S) 有多少个子集的异或为一个连通图。

    (1leq nleq 10,1leq sleq 60)

    Solution

    不妨记 (f_x) 为连通块个数至少(x) 的方案数, (g_x) 为连通块恰好(x) 的方案数。

    容易得到:

    [f_x=sum_{i=x}^negin{Bmatrix}i\xend{Bmatrix}g_i]

    其中第二类斯特林数的含义是将 (i) 个连通块塞成 (x) 个的方案数。至于为什么要塞成 (x) 个,这和 (f) 的计算方式有关,之后会提到。

    那么由斯特林反演

    [g_x=sum_{i=x}^n(-1)^{i-x}egin{bmatrix}i\xend{bmatrix}f_i]

    那么

    [egin{aligned}g_1&=sum_{i=1}^n(-1)^{i-1}egin{bmatrix}i\1end{bmatrix}f_i\&=sum_{i=1}^n(-1)^{i-1}(i-1)!f_iend{aligned}]

    考虑如何求 (f) ,我们可以去枚举子集划分,对于横跨两个集合的边,我们必须让他们异或为 (0) ,集合内的边可以随意连,我们不用管(这样可能会导致集合内不连通,这就是上面第二类斯特林数的含义)。

    这样我们可以用 (O(bell(n))) 的时间枚举子集划分。然后对于每一个划分,用线性基找出边集的极大线性无关组个数,记为 (tot) ,那么在当前集合划分下方案为 (2^{s-tot})

    总复杂度 (O(bell(n)sfrac{n(n-1)}{2}))

    Code

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    char ch[120];
    ll t, x, bin[64], fac[64], ans, base[64], mp[64];
    int s, n, belong[64];
    
    void cal(int sz) {
        t = 0; int cnt = 0;
        for (int i = 0; i < 64; i++) base[i] = 0;
        for (int i = 1, l = -1; i <= n; i++)
            for (int j = i+1; j <= n; j++)
                t |= bin[++l]*(belong[i] != belong[j]);
        for (int j = 1; j <= s; j++) {
            x = t&mp[j];
            for (int i = 63; i >= 0; i--)
                if (x&bin[i]) {
                    if (!base[i]) {base[i] = x; ++cnt; break; }
                    else x ^= base[i];
                }
        }
        if (sz&1) ans += fac[sz-1]*bin[s-cnt];
        else ans -= fac[sz-1]*bin[s-cnt];
    }
    void dfs(int x, int sz) {
        if (x > n) {cal(sz); return; }
        for (int i = 1; i <= sz+1; i++)
            belong[x] = i, dfs(x+1, sz+(i == sz+1));
    }
    void work() {
        scanf("%d", &s); bin[0] = fac[0] = 1;
        for (int i = 1; i <= 10; i++) fac[i] = 1ll*fac[i-1]*i;
        for (int i = 1; i < 64; i++) bin[i] = bin[i-1]<<1;
        scanf("%s", ch+1);
        for (int len = strlen(ch+1); n*(n-1)/2 < len; ++n);
        for (int i = 1, t = 0; i <= n; i++)
            for (int j = i+1; j <= n; j++)
                if (ch[++t] == '1') mp[1] |= bin[t-1];
        for (int T = 2; T <= s; T++) {
            scanf("%s", ch+1);
            for (int i = 1, t = 0; i <= n; i++)
                for (int j = i+1; j <= n; j++)
                    if (ch[++t] == '1') mp[T] |= bin[t-1];
        }
        dfs(1, 0); printf("%lld
    ", ans);
    }
    int main() {work(); return 0; }
  • 相关阅读:
    浙大数据结构课后习题 练习二 7-2 Reversing Linked List (25 分)
    浙大数据结构课后习题 练习二 7-2 一元多项式的乘法与加法运算 (20 分)
    浙大数据结构课后习题 练习一 7-1 Maximum Subsequence Sum (25 分)
    浙大数据结构课后习题 练习一 7-1 最大子列和问题 (20 分)
    PAT Basic 1019 数字黑洞 (20 分)
    PAT Basic 1017 A除以B (20 分)
    PAT Basic 1013 数素数 (20 分)
    PAT Basic 1007 素数对猜想 (20 分)
    PAT Basic 1003 我要通过! (20 分)
    自动化运维——HelloWorld(一)
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/9281209.html
Copyright © 2011-2022 走看看