hdu 6044 dfs+组合数

来源:互联网 发布:怎么搜人名找域名 编辑:程序博客网 时间:2024/05/14 13:35
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个区间,然后让你确定p数列(p数列为1~n中的数),第i个区间【li,ri】表示的是以p【i】为最小值的的最大区间,由此我们也可以得出p[i]<p[li-1]和p[i]<p[ri+1](如果存在的话),我们根据特定的方式给n个区间排序,L升序r降序的方式排序,如果有结果的这样排完序第一个区间一定是[1,n],我们再根据这个大区间分析如果最后有结果的话肯定存在[1,i-1]和[i+1,r]这两个区间(大区间的是第i个区间),在把这两个小区间看作大区间递归下去,我们会发现这其实类似于我们学的先序遍历,而我们之前排完序的其实与这个先序一一对应的(如果不对应的话就表示最后结果无解)
然后就是结果的求法了
最后结果==左区间值*右区间值*本区间值
左右区间就不用说了,是一个递归过程
当前区间为[li,ri],一共ri-li+1个数,出去我们确定的第i个数还剩ri-li个数,我们要从ri-li个数中选出i-li个数放在第i个数的左边(剩下的当然就是右边了)
本区间值=c(ri-li,i-li);
还要注意这题题卡时间,所以要用到超神读入挂

ac代码:
#include <iostream>#include <bits/stdc++.h>using namespace std;const int Maxn=1e6+5;long long fac[Maxn],inv[Maxn];const int mod = 1e9 + 7;int flag,ph;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;void init()//fac表示i的阶乘%mod的值  inv表示i的阶乘的逆元%mod的值{    inv[0] = fac[0] = inv[1] = fac[1] = 1;    for(int i = 1; i < Maxn; i++)    fac[i] = fac[i - 1] * i % mod;    for(int i = 2; i < Maxn; i++)    inv[i] = (mod - (mod / i)) * inv[mod % i] % mod;//lucas定理求逆元    for(int i = 1; i < Maxn; i++)    inv[i] = inv[i - 1] * inv[i] % mod;}long long get_c(int n,int m){    return (fac[n]*inv[m]%mod)*inv[n-m]%mod;}struct node{    int l,r,id;}a[Maxn];bool cmp(node a,node b){    if(a.l!=b.l)    return a.l<b.l;    else    return a.r>b.r;}long long dfs(int l,int r){    if(flag==0)    return 0;    if(l>r)    return 1;    if(a[ph].l!=l||a[ph].r!=r)    {        flag=0;        return 0;    }    node now=a[ph++];    long long ans=get_c(now.r-now.l,now.id-now.l)*dfs(now.l,now.id-1)%mod;    ans=ans*dfs(now.id+1,now.r)%mod;    return ans;}int main(){    init();    int n,p=0;    while(read(n),!IOerror)    {        p++;        for(int i=0;i<n;i++)        read(a[i].l),a[i].id=i+1;        for(int i=0;i<n;i++)        read(a[i].r);        sort(a,a+n,cmp);        flag=1;        ph=0;        printf("Case #%d: %lld\n",p,dfs(1,n));    }    return 0;}



原创粉丝点击