zoukankan      html  css  js  c++  java
  • 题解 主旋律

    题目传送门

    Description

    响应主旋律的号召,大家决定让这个班级充满爱,现在班级里面有 n 个男生。
    如果 a 爱着 b,那么就相当于 a 和 b 之间有一条 a→b 的有向边。如果这 n 个点的图是强联通的,那么就认为这个班级是充满爱的。
    不幸的是,有一些不好的事情发生了,现在每一条边都可能被摧毁。我作为爱的使者,想知道有多少种摧毁的方式,使得这个班级任然充满爱呢?(说人话就是有多少边的子集删去之后整个图仍然强联通。)

    输入格式

    第一行两个数 n 和 m,表示班级里的男生数和爱的关系数。
    接下来 m 行,每行两个数 a 和 b,表示男生 a 爱着男生 b。同时 a 不等于 b。
    所有男生从 1 到 n 标号。
    同一条边不会出现两遍,但可能出现 a 爱着 b,b 也爱着 a 的情况,这是两条不同的边。

    输出格式

    输出一行一个整数,表示对 109+7 取模后的答案。

    样例

    样例输入

    			
    5 15
    4 3
    4 2
    2 5
    2 1
    1 2
    5 1
    3 2
    4 1
    1 4
    5 4
    3 4
    5 3
    2 3
    1 5
    3 1

    样例输出

    			
    9390

    数据范围与提示

    对于 100\% 的数据满足: n≤15,0≤m≤n(n−1)。

    Solution

    以下问题均在有向图上进行考虑。

    首先我们可以考虑如何计算一个点集的是 DAG 完全子图个数。设这个叫 (D(S)) ,定义 (w(S,T)) 表示 (S o T) 的边数,(h(S))(w(S,S))

    我们可以枚举哪些点入度为 (0),那么我们可以通过容斥得到转移式:

    [D(S)=2^h(S)-sum_{T subset S} (-1)^{|T|+1}D(Sotimes T)2^{w(T,Sotimes T)} ]

    考虑到原问题。我们设 (f(S)) 表示集合 (S) 的是 scc 的完全子图个数,(g(S)) 表示将 (S) 分成奇数个 scc 的方案数减去偶数个 scc 的方案数。(原因见上式)

    同样的,我们可以枚举哪些 scc 在缩点后的图上入度为 (0) ,可以得到转移式:

    [f(S)=2^h(S)-sum_{Tsubseteq S}g(T)2^{w(T,Sotimes T)}2^{h(Sotimes T)} ]

    [g(S)=f(S)-sum_{Tsubset S} f(Sotimes T) imes g(T) ]

    不过需要注意的是你在计算 (g(S)) 的时候需要钦定一下顺序,否则会算重,具体来说可以每次当前的 scc 都必须包含一个固定点。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 1000000007
    #define MAXN 17
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
    
    int n,m,pw[MAXN * MAXN],toS[MAXN],lg[1 << 16],siz[1 << 16],cnt[1 << 16],f[1 << 16],g[1 << 16];
    
    int mul (int a,int b){return 1ll * a * b % mod;}
    int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
    int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
    void Sub (int &a,int b){a = dec (a,b);}
    void Add (int &a,int b){a = add (a,b);}
    
    int lowbit (int x){return x & (-x);}
    int getw (int S1,int S2){
    	int res = 0;
    	while (S1){
    		int now = lowbit(S1);
    		S1 -= now,now = lg[now] + 1;
    		res += siz[toS[now] & S2];
    	}
    	return res;
    }
    
    signed main(){
    	read (n,m),pw[0] = 1;
    	for (Int i = 1;i <= m;++ i) pw[i] = add (pw[i - 1],pw[i - 1]);
    	for (Int i = 1;i < n;++ i) lg[pw[i]] = i;
    	for (Int S = 0;S < (1 << n);++ S) siz[S] = siz[S >> 1] + (S & 1);
    	for (Int i = 1,u,v;i <= m;++ i) read (u,v),toS[u] |= (1 << v - 1);
    	for (Int S = 0;S < (1 << n);++ S) cnt[S] = getw (S,S);
    	for (Int S = 1;S < (1 << n);++ S){
    		int nS = S ^ lowbit(S);
    		for (Int T = nS;T;T = (T - 1) & nS) Sub (g[S],mul (f[S ^ T],g[T]));
    		f[S] = pw[cnt[S]];
    		for (Int T = S;T;T = (T - 1) & S) Sub (f[S],mul (g[T],mul (pw[getw (T,S ^ T)],pw[cnt[S ^ T]])));
    		Add (g[S],f[S]);
    	}
    	write (f[(1 << n) - 1]),putchar ('
    ');
    	return 0;
    } 
    
  • 相关阅读:
    POJ3481(待完善版本,请看注释)
    Heap_Sort金老师模板
    poj2255(Tree_Recover)
    快慢指针
    Link_List
    Perl_Tkx_Canvas绘图功能函数介绍
    配置管理
    变更管理
    合同管理
    收尾存在的问题
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/15120571.html
Copyright © 2011-2022 走看看