您的位置:首页 > 其它

HDU6044-Limited Permutation(fread挂&&阶乘求逆元&&组合数)

2017-08-03 10:56 435 查看


Limited Permutation

                                                               Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072
K (Java/Others)

                                                                                      Total Submission(s): 1779    Accepted Submission(s): 482


Problem Description

As to a permutation p1,p2,⋯,pn from 1 to n,
it is uncomplicated for each 1≤i≤n to
calculate (li,ri) meeting
the condition that min(pL,pL+1,⋯,pR)=pi if
and only if li≤L≤i≤R≤ri for
each 1≤L≤R≤n.

Given the positive integers n, (li,ri) (1≤i≤n),
you are asked to calculate the number of possible permutations p1,p2,⋯,pn from 1 to n,
meeting the above condition.

The answer may be very large, so you only need to give the value of answer modulo 109+7.

 

Input

The input contains multiple test cases.

For each test case:

The first line contains one positive integer n,
satisfying 1≤n≤106.

The second line contains n positive
integers l1,l2,⋯,ln,
satisfying 1≤li≤i for
each 1≤i≤n.

The third line contains n positive
integers r1,r2,⋯,rn,
satisfying i≤ri≤n for
each 1≤i≤n.

It's guaranteed that the sum of n in
all test cases is not larger than 3⋅106.

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.


 

Output

For each test case, output "Case #x: y"
in one line (without quotes), where x indicates
the case number starting from 1 and y denotes
the answer of corresponding case.

 

Sample Input

3
1 1 3
1 3 3
5
1 2 2 4 5
5 2 5 5 5

 

Sample Output

Case #1: 2
Case #2: 3

 

Source

2017 Multi-University Training Contest - Team 1

 

题意:给你n个区间,对于每个区间li,ri,当且仅当li<=L<=i<=R<=ri,满足pi=min(pL,pL+1,pL+2......pR-1,pR),问这样的p序列有几个

解题思路:可以知道对于区间(1,n)一定有一个最小值,所以一定有一个区间是(1,n)(用x表示),那么这个最小值把区间x分成两部分L和R ,所以一定存在为L和R的区间,如果不存在,那么输出0,令f(x)表示符合条件的区间x的排列数,那么f(x)=f(L)*f(R)*C(L+R,L) (C()表示组合数,L表示区间L的大小),只需要从区间(1,n)进行深搜即可,因为数据太大取模需要用到阶乘的逆元

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>

using namespace std;

#define LL long long
const int INF = 0x3f3f3f3f;
const LL mod=1000000007;

int l[1000009],r[1000009];
LL ans;
LL mul[1000009],inv[1000009];
map<pair<int,int>,int> mp;

inline char get()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

template <class T> inline bool read(T & x)
{
char ch=get();
if(ch==EOF) return false;
while (ch<'0' || ch>'9') ch = get();
x=ch-'0';
while ((ch = get()) >= '0'&&ch <= '9') x = x * 10 + ch - '0';
return true;
}

void init()
{
mul[0]=1;
for(int i=1; i<1000009; i++)
mul[i]=(mul[i-1]*i)%mod;
inv[0]=inv[1]=1;
for(int i=2; i<1000009; i++)
inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
for(int i=1; i<1000009; i++)
inv[i]=(inv[i-1]*inv[i])%mod;
}

LL C(int n,int m)
{
return mul
*inv[m]%mod*inv[n-m]%mod;
}

void dfs(int l,int r)
{
if(ans==0||r<l) return;
int k=mp[make_pair(l,r)];
if(k==0) {ans=0;return;}
if(l==r) return;
int len=r-l;
ans=(ans*C(len,k-l))%mod;
dfs(l,k-1);
dfs(k+1,r);
}

int main()
{
int n,cas=0;
init();
while(read(n))
{
mp.clear();
ans=1;
for(int i=1; i<=n; i++) read(l[i]);
for(int i=1; i<=n; i++)
{
read(r[i]);
mp[make_pair(l[i],r[i])]=i;
}
dfs(1,n);
printf("Case #%d: %lld\n",++cas,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: