CF1763D Valid Bitonic Permutations

该文阐述了一个编程挑战,涉及找到在一定条件下的位序排列(Bitonicpermutation)数量。问题中给定5个整数n,l,r,x,y,要求找到从1到n的所有数字中,满足特定位置i的值为x,位置j的值为y的升序到降序的位序排列的数量。解决方案包括对x和y的预处理,以及对最高点位置i的枚举,并计算不同区间的组合数。最后,使用组合数学公式计算出答案,并对大整数进行模运算以防止溢出。
摘要由CSDN通过智能技术生成

题目描述

You are given five integers n n n , i i i , j j j , x x x , and y y y . Find the number of bitonic permutations B B B , of the numbers 1 1 1 to n n n , such that B i = x B_i=x Bi=x , and B j = y B_j=y Bj=y . Since the answer can be large, compute it modulo 1 0 9 + 7 10^9+7 109+7 .

A bitonic permutation is a permutation of numbers, such that the elements of the permutation first increase till a certain index k k k , 2 ≤ k ≤ n − 1 2 \le k \le n-1 2kn1 , and then decrease till the end. Refer to notes for further clarification.

题意简述

有五个整数 n , l , r , x , y n,l,r,x,y n,l,r,x,y 和一个长度为 n n n 的排列 a a a,其中 a l = x , a r = y a_l=x,a_r=y al=x,ar=y。求有多少个排列满足先升后降。

题解

首先对 x , y x,y x,y 进行处理,若 x > y x>y x>y,则把整个排列翻转,这样, x x x 小于 y y y 方便后面计算。当然, l , r l,r l,r 也要跟着翻转分别变为 n − l + 1 , n − r + 1 n-l+1,n-r+1 nl+1,nr+1

枚举最高点 n n n 在位置 i i i,此时分三种情况考虑:

  1. i i i 在区间 ( l , r ) (l,r) (l,r) 内,这里放个图方便理解
    1方便起见,首先考区间 ( i , r ) (i,r) (i,r) 内的方案,区间内有 n − y − 1 n-y-1 ny1 个数可以选,有 r − i − 1 r-i-1 ri1 个位置可以放,方案数为 ( n − y − 1 r − i − 1 ) \dbinom{n-y-1}{r-i-1} (ri1ny1)
    接着考虑区间 ( l , i ) (l,i) (l,i) 内的方案,这时就有些复杂了。由于前面 n − y − 1 n-y-1 ny1 个数并没有完全选完,而没选完的这些数只能放在区间 ( l , i ) (l,i) (l,i) 内,它们在区间 ( l , i ) (l,i) (l,i) 内已经占了位置,所以区间 ( l , i ) (l,i) (l,i) 内有 i − l − 1 − ( n − y − 1 − ( r − i − 1 ) ) i-l-1-\left(n-y-1-\left(r-i-1\right)\right) il1(ny1(ri1)) 个位置可以放数;有哪些数可以选呢?只能选 x x x y y y 之间的数,因为 y y y n n n 之间的数已经放好了。方案数即为 ( y − x − 1 i − l − 1 − ( n − y − 1 − ( r − i − 1 ) ) ) \dbinom{y-x-1}{i-l-1-\left(n-y-1-\left(r-i-1\right)\right)} (il1(ny1(ri1))yx1)
    还要考虑区间 [ 1 , l ) [1,l) [1,l) 的情况,方案数就是 ( x − 1 l − 1 ) \dbinom{x-1}{l-1} (l1x1)
    至于区间 ( y , n ] (y,n] (y,n] 就选剩下的,方案数就是 1 1 1
    把方案乘起来即为对答案的贡献。
  2. i i i 在区间 ( r , n ) (r,n) (r,n) 内,如图
    2
    这个情况就比较简单,区间 ( r , i ) (r,i) (r,i) 的方案数为 ( n − y − 1 i − r − 1 ) \dbinom{n-y-1}{i-r-1} (ir1ny1),区间 ( l , r ) (l,r) (l,r) 的方案数为 ( y − x − 1 r − l − 1 ) \dbinom{y-x-1}{r-l-1} (rl1yx1),区间 [ 1 , l ) [1,l) [1,l) 的方案数为 ( x − 1 l − 1 ) \dbinom{x-1}{l-1} (l1x1),区间 ( i , n ] (i,n] (i,n] 选剩下的。
    把方案乘起来即为对答案的贡献。
  3. 还有一种情况要特判: y = n y=n y=n,这种情况要特判,不用枚举最高点。
    在这里插入图片描述
    这种情况也比较简单,区间 ( l , i ) (l,i) (l,i) 的方案数为 ( n − x − 1 r − l − 1 ) \dbinom{n-x-1}{r-l-1} (rl1nx1),区间 [ 1 , l ) [1,l) [1,l) 的方案数为 ( x − 1 l − 1 ) \dbinom{x-1}{l-1} (l1x1),区间 ( r , n ] (r,n] (r,n] 选剩下的。
    对答案的贡献为二者乘积。
    这里还有个点很坑,如果 r = n r=n r=n 就不可能出现排列先升后降的情况,应该输出 0 0 0

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n,l,r,x,y;
ll f[1001],inv[1001];
ll ksm(ll a,ll b)
{
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
ll c(int n,int m)
{
    if(n<m||n<0||m<0) return 0;
    return f[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
    f[0]=1;
    for(int i=1;i<=1000;i++) f[i]=f[i-1]*i%mod;
    inv[1000]=ksm(f[1000],mod-2);
    for(int i=999;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
    int t;
    cin>>t;
    while(t--){
        cin>>n>>l>>r>>x>>y;
        if(x>y) l=n-l+1,r=n-r+1,swap(x,y),swap(l,r);
        if(y==n){
            if(r==n) puts("0");
            else cout<<c(n-x-1,r-l-1)*c(x-1,l-1)%mod<<endl;
            continue;
        }
        ll ans=0;
        for(int i=l+1;i<r;i++){
            ans=(ans+c(n-y-1,r-i-1)*c(y-x-1,r-l+y-1-n)%mod*c(x-1,l-1))%mod;
        }
        for(int i=r+1;i<n;i++){
            ans=(ans+c(n-y-1,i-r-1)*c(y-x-1,r-l-1)%mod*c(x-1,l-1))%mod;
        }
        cout<<ans<<endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值