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

针对给定的区间限制,此算法解决寻找所有可能的排列数量问题,并通过递归搜索结合组合数学方法高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 # 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个区间,对于每个区间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 long
const 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值