题意:
对于一个 1 ~ n 的排列 a[n],假设 a[i] 为可能的最大的区间 [l, r] 范围内的最小值。
对于每一个 a[i], 都有这样的 l[i] 与 r[i].
现给定 l[i] 与 r[i], 问有多少种符合的排列。
推荐:
http://blog.csdn.net/qq_31759205/article/details/76146845
思路:
对于整个区间内的最小值 a[k], 其左右端点必然分别为 1, n, 其将序列分成了 1 ~ k - 1 与 k + 1 ~ n 两部分;
左半部分的最小值 a[k1], 其左右端点必然分别为 1, k - 1, 其将序列分成了 1 ~ k1 - 1 与 k1 + 1 ~ k - 1 两部分,
右半部分的最小值 a[k2], 其左右端点必然分别为 k + 1, n, 其将序列分成了 k1 + 1 ~ k2 - 1 与 k2 + 1 ~ n 两部分;
……
这样,子问题的性质就很明显了,可以用递归来解决。
不可能构成的情况即为找不到一个区间满足上述的划分。
记 u 为区间 [l, r] 的划分点,左子树为 [l, u - 1], 右子树为 [u + 1, r], f 为某段区间的可能排列数
则 f([l, r]) = f([l, u -1]) * f([u + 1, r]) * C(l - r, u - l).
求组合数时,因为 n 太大,不可能直接求,也不可能递推。
于是又学到了一招:乘法逆元。
详情见:http://blog.csdn.net/lu_1110/article/details/52151335
事实上,用递归是过不了最后五组数据的0 0但是在hdu上能过
大概看了一下数据,最后一组是一个单调减的数列,这样递归的层数太深了显然会爆。
(标程写得太迷了也不想看目前就这样先凑合着吧((叹
AC代码如下:
#include <cstdio>
#include <algorithm>
#include <iostream>
#define maxn 1000000
using namespace std;
typedef long long LL;
LL U[maxn + 10], D[maxn + 10];
const LL mod = 1e9 + 7;
int kas, n, cnt;
bool flag;
template<typename T> inline void readint(T &x) {
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
x *= f;
}
namespace IO {
const int MX = 4e7;
char buf[MX]; int c, sz;
void begin() {
c = 0;
sz = fread(buf, 1, MX, stdin);
}
inline bool read(int &t) {
while(c < sz && buf[c] != '-' && (buf[c] < '0' || buf[c] > '9')) c++;
if(c >= sz) return false;
bool flag = 0; if(buf[c] == '-') flag = 1, c++;
for(t = 0; c < sz && '0' <= buf[c] && buf[c] <= '9'; c++) t = t * 10 + buf[c] - '0';
if(flag) t = -t;
return true;
}
}
struct node {
int l, r, id;
}a[maxn + 10];
LL poww(LL a, LL b) {
LL ret = 1;
while (b) {
if (b & 1) ret = ret * a % mod;
a = a * a % mod;
b >>= 1;
}
return ret;
}
void pre() {
U[0] = D[0] = U[1] = D[1] = 1;
for (int i = 2; i <= maxn; ++i) U[i] = U[i - 1] * i % mod;
for (int i = 2; i <= maxn; ++i) D[i] = poww(U[i], mod - 2);
}
bool cmp(node u, node v) {
return u.l < v.l || (u.l == v.l && u.r > v.r);
}
LL C(LL a, LL b) {
// printf("%lld %lld\n", a, b);
return U[a] * D[b] % mod * D[a - b] % mod;
}
LL dfs(int l, int r) {
if (flag) return 0;
if (l > r) return 1;
++cnt;
if (a[cnt].l != l || a[cnt].r != r) { flag = true; return 0; }
if (l == r) return 1;
int temp = cnt;
LL x1 = dfs(l, a[temp].id - 1);
LL x2 = dfs(a[temp].id + 1, r);
return x1 * x2 % mod * C(a[temp].r - a[temp].l, a[temp].id - a[temp].l) % mod;
}
void work() {
for (int i = 1; i <= n; ++i) { IO::read(a[i].l); a[i].id = i; }
for (int i = 1; i <= n; ++i) IO::read(a[i].r);
flag = false;
sort(a + 1, a + n + 1, cmp);
cnt = 0;
printf("Case #%d: %d\n", ++kas, dfs(1, n));
}
int main() {
IO::begin();
pre();
while (IO::read(n)) work();
return 0;
}