HDU

来源:互联网 发布:做淘宝美工怎么样 编辑:程序博客网 时间:2024/06/04 18:21

题目链接:HDU - 6044 - Limited Permutation

放一个博客:HDU-6044 (计数) - 十分残念的博客 - CSDN博客
题意是给定 n 个区间 [li,ri]pi[L,R] 中最小的数字当且仅当 liLiRri 。求出有多少种排列满足上述要求。

对于一个区间 [li,ri]pi 是其中最小的数,因此区间还可分为 [li,i1][i+1,ri] ,其中 pjpk 分别为其中最小的数字。
因此将所有区间按 li 递增, ri 递减的顺序排序。第一个区间一定要是 [1,n] ,然后可以分成区间 [1,i1][i+1,n] ,其中 [1,i1] 是第 i+1 个区间,然后继续递归下去。(这种递归过程形象的看就像是在线段树上进行先序遍历)。
然后将数字进行分配。
假设 f(i) 为第 i 个区间的方案数,那么 f(i)=f(j)f(k)Cilirili
答案为 f([1,n])

#include<bits/stdc++.h>using namespace std;typedef long long ll;const ll mod=1e9+7;const int N=1e6+7;int n;ll frac[N],inv[N];struct Seg{    int l,r,id;    bool operator < (const Seg& t) const    {        return l<t.l||(l==t.l&&r>t.r);    }}seg[N];namespace IO {    const int MX = 4e7;    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;    }}int cur;bool ok;ll power(ll a, ll b){    ll c=1;    while(b)    {        if(b&1) c=c*a%mod;        a=a*a%mod;        b>>=1;    }    return c;}void init(){    frac[0]=1;    for(int i=1;i<N;++i) frac[i]=frac[i-1]*i%mod;    for(int i=1;i<N;++i) inv[i]=power(frac[i],mod-2);}ll C(ll n, ll m){    if(m==0||m==n) return 1;    return frac[n]*inv[m]%mod*inv[n-m]%mod;}ll dfs(int l, int r){    if(!ok) return 0;    if(l>r) return 1;    if(seg[cur].l!=l||seg[cur].r!=r)    {        ok=false;        return 0;    }    int id = seg[cur++].id;    ll res=dfs(l,id-1)*dfs(id+1,r)%mod*C(r-l,id-l)%mod;    return res;}int main(){    int T=1;    init();    IO::begin();    while(IO::read(n))    {        for(int i=0;i<n;++i)            IO::read(seg[i].l);        for(int i=0;i<n;++i)            IO::read(seg[i].r),seg[i].id=i+1;        sort(seg,seg+n);        cur=0;        ok=true;        printf("Case #%d: %I64d\n",T++,dfs(1,n));    }    return 0;}