地址
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,Ri , Lj,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);
}
}