zoukankan      html  css  js  c++  java
  • HDU 6044--Limited Permutation(搜索+组合数+逆元)

    题目链接

    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
    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
     
    题意:对于一个由1~n组成的排列称为合法的,必须满足这样的条件: 有n个(li,ri),对于每个 i 必须满足 min(pL,pL+1,,pR)=pi if and only if liLiRri for each 1LRn.

               现在给了n个(li,ri)求满足的排列有多少个。

    思路:对于每个(li,ri),a[li-1]<a[i]>a[ri+1] ,并且a[i]是a[li]~a[ri]的最小值,那么可以想到:对于区间(1,n)一定有一个最小值,所以一定有一个区间是(1,n)(用X表示),那么这个最小值把区间X分成两部分U和V ,所以一定存在为U和V的区间,如果不存在,那么输出0,令f(X)表示符合条件的区间X的排列数,那么f(X)=f(U)*f(V)*C(U+V+1,U)   【注:C()表示组合数,U 表示区间U的大小】,所以我们只需要从区间(1,n)进行深搜即可,其中因为数据太大取模会用到逆元和组合数。

    代码如下:

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    typedef long long LL;
    const int N=1e6+5;
    const LL mod=1e9+7;
    LL fac[N], Inv[N];
    /*int Scan()///输入外挂
    {
        int res=0,ch,flag=0;
        if((ch=getchar())=='-')
            flag=1;
        else if(ch>='0'&&ch<='9')
            res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')
            res=res*10+ch-'0';
        return flag?-res:res;
    }*/
    namespace IO {
        const int MX = 4e7; //1e7占用内存11000kb
        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;
        }
    }
    
    void Init(){
        fac[0] = Inv[0] = fac[1] = Inv[1] = 1;
        for(int i=2; i<N; i++) fac[i] = fac[i-1] * i % mod;
        for(int i=2; i<N; i++) Inv[i] = (mod - mod / i) * Inv[mod % i] % mod;
        for(int i=2; i<N; i++) Inv[i] = Inv[i] * Inv[i-1] % mod;
    }
    LL C(LL n, LL m){
        LL ans = fac[n] * Inv[m] % mod* Inv[n-m] %mod;
        return ans;
    }
    int ii;
    struct Node{
        int l,r;
        int id;
    }a[N];
    bool cmp(const Node s1,const Node s2)
    {
        if(s1.l==s2.l) return s1.r>s2.r;
        return s1.l<s2.l;
    }
    LL dfs(int L,int R)
    {
        if(a[ii].l!=L || a[ii].r!=R)  return 0;
        int m=a[ii++].id;
        LL fL=1,fR=1;
        if(L<=m-1) fL=dfs(L,m-1);
        if(m+1<=R) fR=dfs(m+1,R);
        LL c=C(R-L,m-L);
        return fL*fR%mod*c%mod;
    }
    int main()
    {
        Init();
        int n,Case=1;
        IO::begin();
        while(IO::read(n))
        {
           for(int i=1;i<=n;i++)  IO::read(a[i].l);
           for(int i=1;i<=n;i++)  IO::read(a[i].r), a[i].id = i;
           sort(a+1,a+n+1,cmp);
           ii=1;
           LL ans=dfs(1,n);
           printf("Case #%d: %lld
    ",Case++,ans);
        }
        return 0;
    }
  • 相关阅读:
    Spring 注解注入—@Qualifier 注释
    Spring基于 @Autowired 和@Required区别与联系
    Spring基于注解@Required配置
    MySQL存储过程---变量的应用
    MySQL存储过程---基础
    MySQL中的变量
    MySQL内置函数-单行函数(流程控制函数)
    MySQL内置函数-版本、用户等函数
    MySQL内置函数-单行函数(字符函数)
    MySQL内置函数-单行函数(日期函数)
  • 原文地址:https://www.cnblogs.com/chen9510/p/7258595.html
Copyright © 2011-2022 走看看