HDU 6044 Limited Permutation dfs 统计

来源:互联网 发布:云计算的优缺点 编辑:程序博客网 时间:2024/05/21 06:30

地址

http://acm.hdu.edu.cn/showproblem.php?pid=6044

题意

给出n,(li,ri),(1<=i<=n),(1<=n<=106),问合法排列的方案数,一个合法的排列满足对li<=L<=i<=R<=ri,总有min(pL,pL+1,...,pR)==pi

思路

对一个区间[L,R],当前区间总有一个最小的数,因为这个数对应的Li,Ri会覆盖整个区间,因为这个数是当前区间的最小数,所以这个数会把区间划分成左右两个部分,这两个部分因为被两者之间的最小数隔开,变成了完全独立的子问题,于是递归下去。

当递归到只有一个数时,这个区间返回方案数1(长度为1的排列当然只有1个方案),一个区间的方案数就是其两个子区间的方案数相乘再乘上C(siz[l]+siz[r],siz[l]),因为左右两个区间是独立的子问题,所以把当前区间的数分给左右区间有组合数种方案,左右区间拿到自己的数后,就有自己原有的方案数。

标程用的笛卡尔树的做法可以用O(n)的预处理,O(1)的查询代替使用sort()进行O(nlogn)的预处理和使用lower_bound()带来的O(logn)的查询。

不难发现,不可能有两个Li,RiLj,Rj完全相同,而且每个区间一定有一个可以覆盖其整个区间的最小数。反之无解。

代码

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int IOMX = 4096;char buf[IOMX], IOt[50];int bi = IOMX, bn = IOMX;int read(char *s) {    while (bn) {        for (; bi < bn && buf[bi] <= ' '; ++bi);        if (bi < bn) break;        bn = fread(buf, 1, IOMX, stdin);        bi = 0;    }    int sn = 0;    while (bn) {        for (; bi < bn && buf[bi] > ' '; ++bi) s[sn++] = buf[bi];        if (bi < bn) break;        bn = fread(buf, 1, IOMX, stdin);        bi = 0;    }    s[sn] = 0;    return sn;}bool read(int &x) {    if (!read(IOt)) return false;    x = atoi(IOt);    return true;}#define lowbit(x) (x & (-x))typedef long long LL;const int MAXN = 1e6 + 5;const int MOD = 1e9 + 7;struct Node {  int l, r, pos;  Node(int l = 0, int r = 0, int pos = 0): l(l), r(r), pos(pos) {}  bool operator<(const Node &node) {    return l < node.l || (l == node.l && r < node.r);  }  bool operator==(const Node &node) {    return l == node.l && r == node.r;  }};int n;int tree_array[MAXN];LL ans;LL factorail_num[MAXN], inv_factorail[MAXN];bool no_solution;Node nodes[MAXN];inline LL Pow(LL a, LL b) {  LL ret = 1;  for (; b; b >>= 1) {    if (b & 1) (ret *= a) %= MOD;    (a *= a) %= MOD;  }  return ret;}inline LL C(int n, int m) {  return factorail_num[n] * inv_factorail[m] % MOD * inv_factorail[n - m] % MOD;}LL dfs(int l, int r) {  if (l > r) return 1;  int idx = lower_bound(nodes, nodes + n, Node(l, r)) - nodes;  if (idx == n || nodes[idx].l != l || nodes[idx].r != r) no_solution = true;  if (no_solution) return 0;  if (l == r) return 1;  LL ret1 = dfs(l, nodes[idx].pos - 1);  LL ret2 = dfs(nodes[idx].pos + 1, r);  return C(r - l, nodes[idx].pos - l) * ret1 % MOD * ret2 % MOD;}int main() {  factorail_num[0] = inv_factorail[0] = 1;  for (int i = 1; i < MAXN; ++i) {    factorail_num[i] = (factorail_num[i - 1] * i) % MOD;    inv_factorail[i] = (inv_factorail[i - 1] * Pow(i, MOD - 2)) % MOD;  }//  cout << C(5, 1) << endl;//  cout << C(6, 3) << endl;  int kase = 0;//  while (~scanf("%d", &n)) {//    for (int i = 0; i < n; ++i) scanf("%d", &nodes[i].l);//    for (int i = 0; i < n; ++i) scanf("%d", &nodes[i].r);  while (read(n)) {    for (int i = 0; i < n; ++i) read(nodes[i].l);    for (int i = 0; i < n; ++i) read(nodes[i].r);    for (int i = 0; i < n; ++i) nodes[i].pos = i + 1;    no_solution = false;    sort(nodes, nodes + n);    for (int i = 1; i < n; ++i) if (nodes[i - 1] == nodes[i]) no_solution = true;    ans = dfs(1, n);    printf("Case #%d: %I64d\n", ++kase, ans);  }}
原创粉丝点击