题意:

  一个有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. Android 解决下拉刷新控件和ScrollVIew的滑动冲突问题。

    最近项目要实现ScrollView中嵌套广告轮播图+RecyleView卡片布局,并且RecyleView按照header和内容的排列样式,因为RecyleView的可扩展性很强,所以我毫无疑问的选择 ...

  2. jQuery学习(三)——选择器总结

    1.基本选择器 id选择器:$(“#id名称”); 元素选择器:$(“元素名称”); 类选择器:$(“.类名”); 通配符:* 多个选择器共用(并集) 案例代码: <!DOCTYPE html& ...

  3. codeforces 493 D Vasya and Chess【 博弈 】

    题意:给出n*n的棋盘,白方在(1,1),黑方在(1,n)处,每一步可以上下左右对角线走,哪个先抓到另一个,则它获胜 可以画一下,发现n是奇数的时候,白方先走,无论它怎么走,黑方和它走对称的,黑方都一 ...

  4. 视图层 view

    视图层是 Django 处理请求的核心代码层,我们大多数 Python 代码都集中在这一层面.它对外接收用户请求,对内调度模型层和模版层,统合数据库和前端,最后根据业务逻辑,将处理好的数据,与前端结合 ...

  5. js对象追加到数组里

    描述:将一个点击事件得到的对象追加到数组里 做法:全局声明一个数组,,在对象的点击事件里将得到的对象追加到数组 change(a){ arr.push(a) console.log(arr) var ...

  6. 小程序canvas生成二维码图片踩的坑

    1:生成临时图片,保证画布被加载以及渲染(即本身不可以 hidden 或是 上级元素不可以 hidden 或是 wx:if 隐藏等) == > 建议:因为 canvas 的组件层级(z-inde ...

  7. HDU-4370 '0 or 1' 最短路 要考虑连通性

    题目链接:https://cn.vjudge.net/problem/HDU-4370 题意 给一个矩阵C(nn),要我们找到一个矩阵X(nn),满足以下条件: X_{12}+X_{13}+...X_ ...

  8. 【codeforces 314C】Sereja and Subsequences

    [题目链接]:http://codeforces.com/problemset/problem/314/C [题意] 让你从n个元素的数组中选出所有的不同的非递减子数列; 然后计算比这个子数列小的和它 ...

  9. HDU——T 2444 The Accomodation of Students

    http://acm.hdu.edu.cn/showproblem.php?pid=2444 Time Limit: 5000/1000 MS (Java/Others)    Memory Limi ...

  10. sqoop从mysql导入到hdfs出现乱码问题

    最近把hive元数据库的快照数据导入到hdfs中,以便对历史的元数据进行查询. 命令如下: sqoop import -D mapred.job.queue.name=do.production -- ...