zoukankan      html  css  js  c++  java
  • BZOJ3812主旋律

    /*
    这道题其实没有看懂  所以整理一下吧
    首先思想转化成所有方案减去不强联通的方案
    不强联通的方案相当于很多强联通分量缩点后的dag
    转化成子问题, 问很多点的dag方案数
    然后枚举作为出度为0的点集 T, 然后S - T和T之间的边是随便连的
    但是由于S-T中你不能保证不包含出度为0的点, 所以要容斥
    最后得到一个式子
    f(S) = sum{T elong S T != kongji}  (-1) ^ {|T| - 1} f(S - T) * 2 ^{way(S - T, T)}
    ways 函数我们可以通过预先状压一遍求出来
    但是这样再转化成原来问题我们需要枚举强联通分量, 显然复杂度不对
    
    然后我们考虑上面那个dp实际上的贡献
    我们枚举所有没有出边的强联通分量缩成的点集合T, 假如T中的点组成奇数个强联通分量, 那么对于答案的贡献系数就是1, 否则是-1
    用g(S)表示将S分成若干个强联通分量的方案数, 当然这里是要合并进去系数的, F(S)表示S的强联通子图的个数
    然后就可以得到G(S) =  F(S) - sum{Telong S, u  T} F(T) g(S - T) (为啥总感觉有一种反演思想)
    那么
    F(S) = 2 ^ (h(S)) - sum{T elong S T != 0} 2 ^ way(T, S - T) + (h(S - T)) g(T)
    然后子集dp就好了
    
    
    
    
    */
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<cmath>
    #define ll long long
    #define M 15
    #define mmp make_pair
    using namespace std;
    int read() {
        int nm = 0, f = 1;
        char c = getchar();
        for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
        for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0';
        return nm * f;
    }
    const int mod = 1000000007;
    void add(int &x, int y) {
        x += y;
        x -= x >= mod ? mod : 0;
        x += x < 0 ? mod : 0;
    }
    int poww[100000], f[1 << M], g[1 << M], h[1 << M], p[1 << M], in[1 << M], out[1 << M], bit[1 << M], n, m;
    int main() {
        n = read(), m = read();
        poww[0] = 1;
        for(int i = 1; i < n * n; i++) poww[i] = (poww[i - 1] << 1) % mod;
        for(int i = 1; i < 1 << n; i++) bit[i] = bit[i - (i & -i)] + 1;
        for(int i = 1; i <= m; i++) {
            int x = read(), y = read();
            x = 1 << (x - 1), y = 1 << (y - 1);
            out[x] |= y, in[y] |= x;
        }
        for(int s = 1; s < 1 << n; s++) {
            int mad = s & -s, outside = s ^ mad;
            for(int i = outside; i; i = (i - 1) & outside)
                add(g[s], -1ll * f[s ^ i] * g[i] % mod);
            h[s] = h[outside] + bit[in[mad] & outside] + bit[out[mad] & outside];
            f[s] = poww[h[s]];
            for(int i = s; i; i = (i - 1) & s) {
                if(i != s) {
                    int one = (i ^ s) & -(i ^ s);
                    p[i] = p[i ^ one] + bit[out[one] & i] - bit[in[one] & (i ^ s)]; 
                } else p[i] = 0;
                add(f[s], -1ll * poww[h[s ^ i] + p[i]] * g[i] % mod);
            }
            add(g[s], f[s]);
        }
        cout << f[(1 << n) - 1] << "
    ";
        return 0;
    }
  • 相关阅读:
    java 集合框架(十五)Deque
    java 集合框架(十四)Queue
    java 集合框架(十)List
    java 集合框架(四)Set
    java 集合框架(三)Collection
    java 集合框架(一)概述
    java 集合框架(二)Iterable接口
    java I/O框架 (四)文件流
    全零网络IP地址0.0.0.0表示意义详谈
    windows在cmd执行svn 命令
  • 原文地址:https://www.cnblogs.com/luoyibujue/p/10505291.html
Copyright © 2011-2022 走看看