zoukankan      html  css  js  c++  java
  • HDU 4917 Permutation(拓扑排序 + 状压DP + 组合数)

    题目链接 Permutation

    题目大意:给出n,和m个关系,每个关系为ai必须排在bi的前面,求符合要求的n的全排列的个数。

    数据规模为n <= 40,m <= 20。 直接状压DP空间肯定是不够的。

    考虑到m <= 20,说明每个连通块的大小不超过21。

    那么我们分别对每个连通块求方案数,并且把不同的连通块的方案数组合起来即可。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    typedef long long LL;
    
    const LL mod = 1e9 + 7;
    
    const int N = 105;
    
    int n, m, s, cnt;
    int mp[N][N], a[N][N], b[N], col[N], pre[N];
    LL c[N][N], f[1 << 22], ans;
    vector <int> v[N];
    
    void init(){
    	c[0][0] = 1;
    	rep(i, 1, N - 2){
    		c[i][0] = 1;
    		rep(j, 1, i - 1){
    			c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
    			c[i][j] %= mod;
    		
    		}
    		c[i][i] = 1;
    	}
    }
    
    void dfs(int x){
    	col[x] = cnt;
    	for (auto u : v[x]){
    		if (col[u]) continue;
    		dfs(u);
    	}
    }
    
    int main(){
    
    	init();
    
    	while (~scanf("%d%d", &n, &m)){
    
    		rep(i, 0, n + 1) v[i].clear();
    		memset(mp, 0, sizeof mp);
    		memset(col, 0, sizeof col);
    		rep(i, 1, m){
    			int x, y;
    			scanf("%d%d", &x, &y);
    			v[x].push_back(y);
    			v[y].push_back(x);
    			mp[x][y] = 1;
    			mp[y][x] = -1;
    		}
    
    		cnt = 0;
    		rep(i, 1, n) if (!col[i]) ++cnt, dfs(i);
    
    		memset(b, 0, sizeof b);
    		rep(i, 1, n) a[col[i]][b[col[i]]++] = i;
    
    		s = n;
    		ans = 1;
    
    		rep(i, 1, cnt){
    			int maxS = (1 << b[i]) - 1;
    			rep(j, 0, maxS + 2) f[j] = 0;
    			f[0] = 1LL;
    			memset(pre, 0, sizeof pre);
    			rep(j, 0, b[i] - 1){
    				rep(k, 0, b[i] - 1) if (j ^ k){
    					if (mp[a[i][j]][a[i][k]] == 1) pre[k] |= (1 << j);
    				}
    			}
    
    			rep(S, 0, maxS) if (f[S] > 0){
    				rep(j, 0, b[i] - 1){
    					if (((S & pre[j]) == pre[j]) && !(S & (1 << j))){
    						f[S | (1 << j)] += f[S];
    						f[S | (1 << j)] %= mod;
    					}
    				}
    			}
    			
    			ans = ans * f[(1 << b[i]) - 1] % mod * c[s][b[i]] % mod;
    			s -= b[i];			
    		}
    
    		printf("%lld
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [fw]PAGE_SIZE & PAGE_SHIFT & _AC()
    Memory layout of x86_64 in Linux
    Compile Linux Kernel on Ubuntu 12.04 LTS (Detailed)
    ret/retn人为改变执行地址
    [fw]LINUX中断描述符初始化
    查看x86主機是否支援64bit in Linux
    Linux.中断处理.入口x86平台entry_32.S
    [fW]中断处理函数数组interrupt[]初始化
    Linux GNU GAS introduction
    洛谷试炼场 3-5数论 3-17 倍增
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7360238.html
Copyright © 2011-2022 走看看