题意:

  一个有n个数的排列,给你一些位置上数字的大小关系。求合法的排列有多少种。

思路:

  数字的大小关系可以看做是一条有向边,这样以每个位置当点,就可以把整个排列当做一张有向图。而且题目保证有解,所以只一张有向无环图。这样子,我们就可以把排列计数的问题转化为一个图的拓扑排序计数问题。

  拓扑排序的做法可以参见ZJU1346

  因为题目中点的数量比较多,所以无法直接用状压DP。 但是题目中的边数较少,所以不是联通的,而一个连通块的点不超过21个,而且不同连通块之间可以看做相互独立的。所以我们可以对于每个连通块分别求解,然后利用排列组合的知识,把他们组合起来。这样就可以得到最终解了。

代码:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include <time.h> using namespace std; typedef __int64 ll; const int INF = <<;
const int MAXM = ;
const int MAXN = ;
const ll MOD = (ll) 1e9+; ll dp[<<MAXM]; //
ll combine[MAXN][MAXN]; //组合数
int Matrix[MAXN][MAXN]; //邻接矩阵,1表示正向边,-1表示反向边
int tmp[MAXM], pre[MAXM], num; //求每个连通块的拓扑序用
bool vis[MAXN]; //求连通块用
int n, m, tot;
ll ans; void dfs(int u) {
int u2 = num; //当前点的标号
tmp[num++] = u; //把这个点加入集合
vis[u] = true; int v;
for (int i = ; i <= n; i++) if (Matrix[u][i]) { //如果有边
if (!vis[i]) dfs(i); //如果没找过先找后继
if (==Matrix[u][i]) {
for (v = ; v < num; v++) if (tmp[v]==i) {
pre[v] |= (<<u2); //把这个点加入后继的前驱集合
}
}
}
} ll calc() { //计算某个连通块的拓扑数量
memset(dp, , sizeof(dp));
dp[] = ; for (int S = ; S < (<<num); S++) if (dp[S]>)
for (int i = ; i < num; i++) if (((S&pre[i])==pre[i]) && !(S&(<<i))) {
dp[S|(<<i)] = (dp[S|(<<i)]+dp[S])%MOD;
} return dp[(<<num)-];
} void solve() {
memset(vis, false, sizeof(vis));
ans = ;
tot = n;
for (int i = ; i <= n; i++) if (!vis[i]) { //搜连通块
memset(pre, , sizeof(pre)); num = ;
dfs(i);
if (num<) //只有一个或者两个点的情况,拓扑序时确定的
ans = (((num*combine[tot][num])%MOD)*ans)%MOD;
else
ans = (((calc()*combine[tot][num])%MOD)*ans)%MOD; tot -= num;
} printf("%I64d\n", ans);
} int main() {
#ifdef Phantom01
freopen("HDU4917.in", "r", stdin);
// freopen("HDU4917.out", "w", stdout);
#endif //Phantom01 for (int i = ; i < MAXN; i++) { //预处理组合数(杨辉三角)
combine[i][] = ;
for (int j = ; j <= i; j++)
combine[i][j] = (combine[i-][j-] + combine[i-][j])%MOD;
} while (scanf("%d%d", &n, &m)!=EOF) {
memset(Matrix, , sizeof(Matrix));
int u, v;
for (int i = ; i < m; i++) {
scanf("%d%d", &u, &v);
Matrix[u][v] = ;
Matrix[v][u] = -;
}
solve();
} return ;
}

HDU4917

  写的时候,莫名其妙的wa了一发,要数据来对拍才发现是中间结果溢出了……所以,小心的调整运算顺序和适当的加括号很有必要。

HDU 4917 Permutation 拓扑排序的计数的更多相关文章

  1. HDU.2647 Reward(拓扑排序 TopSort)

    HDU.2647 Reward(拓扑排序 TopSort) 题意分析 裸的拓扑排序 详解请移步 算法学习 拓扑排序(TopSort) 这道题有一点变化是要求计算最后的金钱数.最少金钱值是888,最少的 ...

  2. ACM: hdu 2647 Reward -拓扑排序

    hdu 2647 Reward Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Des ...

  3. HDU 2647 Reward (拓扑排序)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2647 题意是给你n点m条有向边,叶子点(出度为0)上的值为888,父亲点为888+1,依次计算... ...

  4. hdu 5438 Ponds 拓扑排序

    Ponds Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/contests/contest_showproblem ...

  5. CF798E. Mike and code of a permutation [拓扑排序 线段树]

    CF798E. Mike and code of a permutation 题意: 排列p,编码了一个序列a.对于每个i,找到第一个\(p_j > p_i\)并且未被标记的j,标记这个j并\( ...

  6. 【NOIP2017】逛公园(最短路图,拓扑排序,计数DP)

    题意: 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花 ...

  7. hdu 4857 逃生 拓扑排序+PQ,剥层分析

    pid=4857">hdu4857 逃生 题目是求拓扑排序,但不是依照字典序最小输出,而是要使较小的数排在最前面. 一開始的错误思路:给每一个点确定一个优先级(该点所能到达的最小的点) ...

  8. HDU 4917 Permutation

    意甲冠军: 序列p1.p2.p3--pn由1.2.3--n这些数字  现在给出一些条件pi<pj  部条件的排列的个数 思路: 非常easy想到用一条有向的线连接全部的pi和pj  那么就构成了 ...

  9. HDU 1285 经典拓扑排序入门题

    确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

随机推荐

  1. SpringMVC(一) 简单代码编写,注解,重定向与转发

    SpringMVC是什么 SpringMVC是目前最好的实现MVC设计模式的框架,是Spring框架的一个分支产品,以SpringIOC容器为基础,并利用容器的特性来简化它的配置.SpringMVC相 ...

  2. (转载) 使用DrawerLayout和NavigationView从右侧出现

    使用DrawerLayout和NavigationView从右侧出现 2016-07-21 17:53 957人阅读 评论(0) 收藏 举报  分类: android(9)  版权声明:本文为博主原创 ...

  3. 51nod 1632 B君的连通

    题目: 这题看起来难,其实这么多概率啥的都是唬人的.甚至连快速幂都不用就可以解. 解法:    n个节点,n-1条边,期望会有一半的边被炸毁(因为总体概率就是50%). 即(n-1)/2条边被炸毁,这 ...

  4. avalon 双工绑定以及一个按钮多个事件

    <html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    ...

  5. UVa 12545 Bits Equalizer【贪心】

    题意:给出两个等长的字符串,0可以变成1,?可以变成0和1,可以任意交换s中任意两个字符的位置,问从s变成t至少需要多少次操作 先可以画个草图 发现需要考虑的就是 1---0 0---1 ?---0 ...

  6. Docker学习笔记(1)----认识Docker

    1. 什么Docker? Docker是一个能把开发的应用程序自动部署到容器的引擎,它使用go语言编写的开源引擎,它在github上面个的地址为:https://github.com/docker/d ...

  7. ZBrush中独特功能Projection Master

    Projection Master可以理解为投影大师,它是ZBrush®的一个独特功能,该功能可以让用户使用所有的2D和2.5D笔刷工具在3D模型上进行雕刻.纹理绘制和其他的操作. 简单来说,Proj ...

  8. SKU和SPU表的设计

    1.什么是SKU,SPU SKU:Stock Keeping Unit (库存量单位)SKU即库存进出计量的单位,可以是以件.盒.托盘等为单位,是物理上不可分割的最小存货单元.在使用时要根据不同业态, ...

  9. 基于 Token 的身份验证:JSON Web Token

    最近了解下基于 Token 的身份验证,跟大伙分享下.很多大型网站也都在用,比如 Facebook,Twitter,Google+,Github 等等,比起传统的身份验证方法,Token 扩展性更强, ...

  10. 页面加载完成触发input[type="file"]控件问题

    由于浏览器厂家的限制,不同的浏览器不开放页面加载完成就允许触发input[type="file"]控件 测试 Chrome .火狐 .IE .微信客户端QQ =>桌面端: C ...