zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    【转】CUDA5/CentOS6.4
    【转】centos 6.4 samba 安装配置
    【转】Install MATLAB 2013a on CentOS 6.4 x64 with mode silent
    【转】Getting xrdp to work on CentOS 6.4
    【VLFeat】使用matlab版本计算HOG
    Unofficial Windows Binaries for Python Extension Packages
    March 06th, 2018 Week 10th Tuesday
    March 05th, 2018 Week 10th Monday
    March 04th, 2018 Week 10th Sunday
    March 03rd, 2018 Week 9th Saturday
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/12056370.html
Copyright © 2011-2022 走看看