Given the positive integers , , you are asked to calculate the number of possible permutations from to , meeting the above condition.
The answer may be very large, so you only need to give the value of answer modulo .
For each test case:
The first line contains one positive integer , satisfying .
The second line contains positive integers , satisfying for each .
The third line contains positive integers , satisfying for each .
It's guaranteed that the sum of in all test cases is not larger than .
Warm Tips for C/C++: input data is so large (about 38 MiB) that we recommend to use fread() for buffering friendly.
size_t fread(void *buffer, size_t size, size_t count, FILE *stream); // reads an array of count elements, each one with a size of size bytes, from the stream and stores them in the block of memory specified by buffer; the total number of elements successfully read is returned.
3 1 1 3 1 3 3 5 1 2 2 4 5 5 2 5 5 5
Case #1: 2 Case #2: 3
欸,直接复制连格式好像都复制过来了,真好。
题目意思大致是说:对于每一个数都会给你一个区间,并且当前数是给定区间内最小的,在这种情况下让你求可能的组合数。
哇,感觉这么说好像不太能理解,那就直接上图吧:(用第二个样例来举例)
如果我们稍微改动一下:
是不是忽然感觉发现了什么?
对于1,它是整个区间的最小,所以是固定了的0.
对于3,在1之后是剩余区间最小,所以是1.
对于2,在1 3之后剩余区间内的某一个长度为1的区间最小
对于4,在1 3之后剩余区间内的某一个长度为2的区间最小
对于5,在4的区间内去掉4的值之后 固定的最小。
所以样例的答案3 来自于对2 和4的区间的分配。
所以题目就好理解了。如果能够用类似的方法建出树,然后就可以在子树合并的时候,用组合数来求了。涉及到的组合数比较大,大概在10W范围内,所以要预处理出阶乘和阶乘的逆元。
O(N)求 1 - N 的逆元:
void init() {
inv[1] = 1;
for(int i = 2; i < maxn; i++) {
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
}
}
5
1 2 1 4 5
1 2 5 4 5
这种情况该怎么弄。子树如果不是只有最多两颗的情况怎么办?
然后大佬给了我解答: if and only if for each .
对不起,我读题有误,我的锅。也就是说建树只有可能是左右两个子树。用官方题解的话,一开始必然存在一个区间覆盖(1, n),这个节点 i 作为父节点,必然存在节点覆盖(i.left, i - 1), (i + 1, i.right)。所以甚至不想建树的话,可以直接递归合并。
到这里差不多就讲完了。不过,如果仅仅是这样,交上去肯定是T了的。题目中也写出要输入优化,所以要输入优化。
还有就是如果这样直接递归,会有爆栈的风险(最后几个样例boom boom boom),所以要加个黑科技:(网上搜的)
#pragma comment(linker, /STACK:102400000,102400000)
这个能打开HDU的栈限制,然就开开心心的不爆栈了。
哦,对了。除了官方提供的加速输入,我也试了一下OI里常有的快速读入,但是快速读入效果不好,直接T了,贴在代码里,有兴趣的同学就别试了。说多了都是泪
代码如下:
#pragma comment(linker, /STACK:102400000,102400000)
#include <bits/stdc++.h>
namespace fastIO {
#define BUF_SIZE 100000
//fread -> read
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) {
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
}
inline void read(int &x) {
char ch;
while(blank(ch = nc()));
if(IOerror)
return;
for(x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
/*
inline bool reand(int & ret) {
char c; int sgn;
if(c = getchar(), c == EOF) return 0;
while(c != '-' && (c < '0' || c > '9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
*/
typedef long long ll;
const ll mod = 1e9 + 7;
const int maxn = 1e6 + 500;
ll ans;
ll inv[maxn], ni[maxn], num[maxn];
void init() {
inv[1] = 1;
ni[0] = ni[1] = inv[1];
num[0] = num[1] = 1;
for(int i = 2; i < maxn; i++) {
num[i] = num[i - 1] * i % mod;
inv[i] = (mod - mod / i) * inv[mod % i] % mod;
ni[i] = ni[i - 1] * inv[i] % mod;
}
}
ll getC(int n, int m) {
return num[n] * ni[m] % mod * ni[n - m] % mod;
}
struct Node{
int l, r, id, len;
}node[maxn];
std::vector<Node> mp[maxn];
int cmp(Node a, Node b) {
if(a.l == b.l) return a.len > b.len;
return a.l < b.l;
}
int binary(int p, int len) {
int l = 0, r = mp[p].size() - 1;
while(l <= r) {
int m = (l + r) >> 1;
if(mp[p][m].len == len) return m;
else if(mp[p][m].len > len) l = m + 1;
else r = m - 1;
}
return -1;
}
bool solve(int p, int len) {
//printf("%d - %d\n", p, len);
if(len == 0) return true;
int pos = binary(p, len);
//printf("----------%d\n", pos);
if(pos == -1) return false;
int id = mp[p][pos].id;
int l = mp[p][pos].l, r = mp[p][pos].r;
if(!solve(l, id - l)) return false;
if(!solve(id + 1, r - id)) return false;
ans = (ans * getC(r - l, std::min(id - l, r - id))) % mod;
//printf("Ans: %lld\n", ans);
return true;
}
int main() {
//freopen("1012.in", "r", stdin);
//freopen("out.out", "w", stdout);
init();
int kase = 0, n;
while(read(n), !fastIO::IOerror) {
//while(reand(n)) {
for(int i = 1; i <= n; i++) mp[i].clear();
ans = 1;
for(int i = 1; i <= n; i++) {
read(node[i].l);
//reand(node[i].l);
}
for(int i = 1; i <= n; i++) {
read(node[i].r);
//reand(node[i].r);
node[i].id = i;
node[i].len = node[i].r - node[i].l + 1;
}
std::sort(node + 1, node + 1 + n, cmp);
for(int i = 1; i <= n; i++) mp[node[i].l].push_back(node[i]);
printf("Case #%d: ", ++kase);
if(solve(1, n)) printf("%lld\n", ans);
else puts("0");
}
return 0;
}