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


    传送门

    题意:
    给出(s,sleq 60)张图,每张图都有(n,nleq 10)个点。
    现在问有多少个图的子集,满足这些图的边“异或”起来后,这张图为连通图。

    思路:

    • 直接考虑判断图的连通不好判断,所以考虑枚举连通块来进行容斥。

    • 定义(f_i)表示有(i)个连通块的答案,发现连通块这个东西也不好处理,我们只能处理出有多少个连通块,但无法确定每个连通块内部的连通关系。

    • 定义(g_i)为至少有(i)个连通块的方案数,那么就有关系式:(displaystyle g_i=sum_{j=i}^n egin{Bmatrix} j \ i end{Bmatrix}f_j)。至于为什么要乘以一个第二类斯特林数,相当于我们将单个的连通块再进行组合,有不同的组合方式。

    • 此时(g_i)就相当于有(i)个连通块,内部可连通可不连通的方案数。

    • 因为最终所求为(f_1),通过斯特林反演可得:(displaystyle f_1=sum_{i=1}^n(-1)^{i-1}egin{bmatrix} i \ 1 end{bmatrix}g_i)。那么现在只需要算(g_i)即可。

    • 因为点数很少,可以直接枚举子集划分,我们只需要保证最后不同的集合之间没有边相连即可。

    • 当确定了一种子集划分过后,将连接不同集合的边拿出来,将每张图这类边转为二进制插入线性基中,最后的基为(c)个,那么答案就为(2^{s-c})

    • 将答案累加入(f_i)即可。

    这个题大概就这样做完了,但还有一些小细节,其中,斯特林反演的时候和常见形式稍有不同,但可以通过反转公式证明:

    [left{ egin{aligned} &sum_{k=m}^n(-1)^{n-k}egin{bmatrix} n \ k end{bmatrix}egin{Bmatrix} k \ m end{Bmatrix}=[n=m]\ &sum_{k=m}^n(-1)^{k-m}egin{Bmatrix} n \ k end{Bmatrix}egin{bmatrix} k \ m end{bmatrix}=[n=m] end{aligned} ight. ]

    最后的答案为(2^{s-c})的原因在于,我们相当于来求若干个数异或起来为(0)的方案数,每个图用(x_i)来表示其最终状态,那么如果有(c)个基,说明就有(s-c)个自由变量,对于任意一组自由变量的取值,我们都能找到一组唯一的对应的解满足方程。
    其实这个本质上就是求解一个异或方程组。
    代码如下:

    /*
     * Author:  heyuhhh
     * Created Time:  2019/12/17 15:36:21
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <vector>
    #include <cmath>
    #include <set>
    #include <map>
    #include <queue>
    #include <iomanip>
    #define MP make_pair
    #define fi first
    #define se second
    #define sz(x) (int)(x).size()
    #define all(x) (x).begin(), (x).end()
    #define INF 0x3f3f3f3f
    #define Local
    #ifdef Local
      #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
      void err() { std::cout << '
    '; }
      template<typename T, typename...Args>
      void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
    #else
      #define dbg(...)
    #endif
    void pt() {std::cout << '
    '; }
    template<typename T, typename...Args>
    void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    //head
    const int N = 105;
    
    int s, n;
    char ch[N];
    int G[N][N][N];
    int a[N];
    ll p[64], fac[N];
    ll ans;
    
    void dfs(int x, int up) {
        if(x == n) {
            memset(p, 0, sizeof(p));
            int c = 0;
            for(int k = 1; k <= s; k++) {
                ll res = 0;
                int tot = 0;
                for(int i = 1; i <= n; i++) {
                    for(int j = i + 1; j <= n; j++) {
                        if(a[i] != a[j]) res |= ((ll)G[k][i][j] << tot);
                        ++tot;
                    }
                }   
                for(int i = tot; i >= 0; i--) if(res >> i & 1) {   
                    if(!p[i]) {
                        ++c; p[i] = res; 
                        break;   
                    }
                    res ^= p[i];
                }
            }
            if(up & 1) ans += fac[up - 1] * (1ll << (s - c));
            else ans -= fac[up - 1] * (1ll << (s - c));
            return;
        }
        for(int i = 1; i <= up + 1; i++) {
            a[x + 1] = i; dfs(x + 1, max(i, up));   
        }
    }
    
    void run(){
        fac[0] = 1;
        for(int i = 1; i < 12; i++) fac[i] = fac[i - 1] * i;
        for(int k = 1; k <= s; k++) {
            cin >> (ch + 1);
            int len = strlen(ch + 1), cnt = 0;
            for(int j = 1; !n; j++) if(j * (j - 1) == 2 * len) n = j;
            for(int i = 1; i <= n; i++) {
                for(int j = i + 1; j <= n; j++) {
                    G[k][i][j] = ch[++cnt] - '0';
                }
            }
        }
        a[1] = 1;
        dfs(1, 1);
        cout << ans << '
    ';
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        cout << fixed << setprecision(20);
        while(cin >> s) run();
        return 0;
    }
    
  • 相关阅读:
    Lining.js
    stdmap 用 at() 取值,如果 key 不存在,不好意思,程序崩溃。QMap 用 value()取值,如果 key 不存在,不会崩溃,你还可以指定默认值
    任正非:美国通信产业失败,不要归罪于华为的崛起(创业过程:前端替客户考虑,后端及时回款建立信誉)
    草根站长赚不到钱的六大原因(失败的理由却只有一个,那就是你不够努力)
    记一次构建SaaS平台项目失败后的反思(收集的客户需求太少,且没有区分重点,闭门造车。技术演变要渐进)
    Qt源码分析之QObject
    Mongodb索引用B树,而Mysql用B+树
    开源工作流elsa-core
    ExpressionTree实现JSON解析器
    分析Ajax爬取
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/12056370.html
Copyright © 2020-2023  润新知