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

来源:互联网 发布:全球数据库软件公司 编辑:程序博客网 时间:2024/06/07 03:33

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 1in to calculate (li,ri) meeting the condition that min(pL,pL+1,,pR)=pi if and only if liLiRri for each 1LRn.

Given the positive integers n(li,ri) (1in), 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 1n106.

The second line contains n positive integers l1,l2,,ln, satisfying 1lii for each 1in.

The third line contains n positive integers r1,r2,,rn, satisfying irin for each 1in.

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

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 #xy" in one line (without quotes), where x indicates the case number starting from 1 and y denotes the answer of corresponding case.
 

Sample Input
31 1 31 3 351 2 2 4 55 2 5 5 5
 

Sample Output
Case #1: 2Case #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 longconst 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[n]*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;}

原创粉丝点击