HDU 4917 Permutation

题意:

一个序列p1、p2、p3……pn是由1、2、3……n这些数字组成的  现给出一些条件pi<pj  问满足所有条件的排列的个数

思路:

很容易想到用一条有向的线连接所有的pi和pj  那么就构成了有向无环图(题中说有解所以无环)

又因为pi各不相同  那么题目就变成了有向无环图的拓扑排序的种类数

题目中边数较少  所以可能出现不连通情况  我们先讨论一个连通集合内拓扑排序的种类数

题目中m较小  可以利用状压后的记忆化搜索解决

现在考虑如果知道了A和B两个集合各自的种类数  如果把它们合起来

由于各自种类已知  我们可以把A和B当成有序的排列  那么问题就变成了将|B|个元素插空到|A|个元素中间

这个可以利用dp解决  同时n较小  我们可以直接打出表

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define N 45
typedef long long LL;

const int mod = (int) 1e9 + 7;
int dp[2][N], f[N][N], in[N], out[N], fa[N], vis[N], qu[N], g[1 << 21];
vector<int> ed[N];
int n, m, ans, top;
struct node {
	int id, fa;
	bool operator<(const node ff) const {
		return fa < ff.fa;
	}
} nd[N];

void init() {
	for (int i = 1; i <= n; i++) {
		in[i] = out[i] = 0;
		fa[i] = i;
		vis[i] = 0;
		ed[i].clear();
	}
	ans = 1;
	top = 0;
}

int getf(int x) {
	if (x != fa[x])
		fa[x] = getf(fa[x]);
	return fa[x];
}

LL topo(int sta) {
	if (g[sta] != -1)
		return g[sta];
	LL res = 0;
	int i, u, j, ss;
	for (i = 0; i < top; i++) {
		u = qu[i];
		if (!vis[u] && !in[u]) {
			vis[u] = 1;
			ss = ed[u].size();
			for (j = 0; j < ss; j++)
				in[ed[u][j]]--;
			res += topo(sta | (1 << i));
			vis[u] = 0;
			for (j = 0; j < ss; j++)
				in[ed[u][j]]++;
		}
	}
	return g[sta] = res % mod;
}

void maketable() {
	int i, j, u, v, from, to;
	for (i = 1; i < N; i++) {
		f[0][i] = 1;
		for (j = i; j < N; j++) {
			for (v = 1; v <= i + 1; v++)
				dp[1][v] = 1;
			to = 1;
			for (u = 2; u <= j; u++) {
				from = (u & 1) ^ 1;
				to = u & 1;
				for (v = 1; v <= i + 1; v++)
					dp[from][v] = (dp[from][v] + dp[from][v - 1]) % mod;
				for (v = 1; v <= i + 1; v++)
					dp[to][v] = dp[from][v];
			}
			for (v = 1; v <= i + 1; v++)
				dp[to][v] = (dp[to][v] + dp[to][v - 1]) % mod;
			f[j][i] = f[i][j] = dp[to][i + 1];
		}
	}
}

int main() {
	int i, j, u, v;
	maketable();
	while (~scanf("%d%d", &n, &m)) {
		init();
		for (i = 1; i <= m; i++) {
			scanf("%d%d", &u, &v);
			if (u == v)
				continue;
			ed[u].push_back(v);
			in[v]++;
			out[u]++;
			u = getf(u);
			v = getf(v);
			if (u != v)
				fa[v] = u;
		}
		for (i = 1; i <= n; i++) {
			nd[i].id = i;
			nd[i].fa = getf(i);
		}
		sort(nd + 1, nd + n + 1);
		nd[n + 1].fa = -1;
		for (i = 1; i <= n; i = j) {
			top = 1;
			qu[0] = nd[i].id;
			for (j = i + 1; j <= n + 1; j++) {
				if (nd[j].fa == nd[i].fa) {
					qu[top++] = nd[j].id;
				} else {
					for (u = 0; u < (1 << top); u++)
						g[u] = -1;
					g[(1 << top) - 1] = 1;
					ans = (LL) ans * (topo(0) * f[i - 1][j - i] % mod) % mod;
					break;
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

HDU 4917 Permutation

时间: 2024-11-01 09:54:36

HDU 4917 Permutation的相关文章

HDU 4917 Permutation 拓扑排序的计数

题意: 一个有n个数的排列,给你一些位置上数字的大小关系.求合法的排列有多少种. 思路: 数字的大小关系可以看做是一条有向边,这样以每个位置当点,就可以把整个排列当做一张有向图.而且题目保证有解,所以只一张有向无环图.这样子,我们就可以把排列计数的问题转化为一个图的拓扑排序计数问题. 拓扑排序的做法可以参见ZJU1346 . 因为题目中点的数量比较多,所以无法直接用状压DP. 但是题目中的边数较少,所以不是联通的,而一个连通块的点不超过21个,而且不同连通块之间可以看做相互独立的.所以我们可以对

hdu 2583 permutation 动态规划

Problem Description Permutation plays a very important role in Combinatorics. For example ,1 2 3 4  5 and 1 3 5 4 2 are both 5-permutations. As everyone's known, the number of n-permutations is n!. According to their magnitude relatives ,if we insert

【数学】HDU 5753 Permutation Bo

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5753 题目大意: 两个序列h和c,h为1~n的乱序.h[0]=h[n+1]=0,[A]表示A为真则为1,假为0. 函数f(h)=(i=1~n)∑ci[hi>hi−1 && hi>hi+1] 现在给定c的值,求f(h)的期望. 题目思路: [数学] 头尾的概率为1/2,中间的概率为1/3,直接求和. 1 // 2 //by coolxxx 3 // 4 #include<io

HDU 4345 Permutation dp

Permutation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 724    Accepted Submission(s): 404 Problem Description There is an arrangement of N numbers and a permutation relation that alter one

HDU 6044--Limited Permutation(搜索+组合数+逆元)

题目链接 Problem Description As to a permutation p1,p2,?,pn from 1 to n, it is uncomplicated for each 1≤i≤n to calculate (li,ri) meeting the condition that min(pL,pL+1,?,pR)=pi if and only if li≤L≤i≤R≤ri for each 1≤L≤R≤n. Given the positive integers n, (

hdu 5753 Permutation Bo

这里是一个比较简单的问题:考虑每个数对和的贡献.先考虑数列两端的值,两端的摆放的值总计有2种,比如左端:0,大,小:0,小,大:有1/2的贡献度.右端同理. 中间的书总计有6种可能.小,中,大.其中有两种对答案有贡献,即1/3的贡献度.加和计算可得到答案. Permutation Bo Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s):

HDU 3664 Permutation Counting (DP)

题意:给一个 n,求在 n 的所有排列中,恰好有 k 个数a[i] > i 的个数. 析:很明显是DP,搞了好久才搞出来,觉得自己DP,实在是太low了,思路是这样的. dp[i][j]表示 i 个排列,恰好有 j 个数,dp[i][j] = dp[i-1][j] * (j+1) + dp[i-1][j-1] * (i-j).这是状态转移方程. 为什么是这样呢,dp[i-1][j] * (j+1) 意思是,你前i-1个已经凑够 j 个了,那么我把 i 可以去替换这个 j 个任何一个,再加上,把这

ACM总结——dp专辑(转)

感谢博主——      http://blog.csdn.net/cc_again?viewmode=list       ----------  Accagain  2014年5月15日 动态规划一直是ACM竞赛中的重点,同时又是难点,因为该算法时间效率高,代码量少,多元性强,主要考察思维能力.建模抽象能力.灵活度. 本人动态规划博客地址:http://blog.csdn.net/cc_again/article/category/1261899 ***********************

模拟2

    ID Origin Title 6 / 10 Problem A HDU 4706 Children's Day 7 / 22 Problem B HDU 4707 Pet 5 / 25 Problem C HDU 4708 Rotation Lock Puzzle 6 / 26 Problem D HDU 4709 Herding 1 / 9 Problem E HDU 4710 Balls Rearrangement     Problem F HDU 4711 Weather