hdu 6044 dfs+组合数

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 # 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

题意:给你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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值