造一造

qq_43520313發表於2020-10-21

題目:
https://ac.nowcoder.com/acm/problem/15077

每次你可以入棧一個新元素或者當棧非空時出棧一個元素, n n n個元素必須依次入棧,而 W Y F WYF WYF希望其中第 m m m個元素入棧之後,棧中恰好有 k k k個元素,現在他想知道一共有多少種入棧出棧順序滿足這個條件。

思路:
首先分成兩個子問題

  • 在第 m m m個元素入棧之前,有 m − 1 m-1 m1個入棧, m − k m-k mk個出棧,並且每一時刻入棧的個數不少於出棧的個數,方案為
    ( 2 m − 1 − k m − 1 ) k m {2m-1-k\choose m-1}\frac{k}{m} (m12m1k)mk
  • 在第 m m m個元素入棧之後,還有有 n − m n-m nm個入棧, n − m + k n-m+k nm+k個出棧,並且每一時刻出棧的個數減入棧的個數小於等於 k k k(棧裡已經有 k k k個元素),方案數為
    ( 2 n − 2 m + k n − m ) k + 1 n − m + k + 1 {2n-2m+k\choose n-m}\frac{k+1}{n-m+k+1} (nm2n2m+k)nm+k+1k+1
    答案就是兩式相乘

注意: 算組合數有不合法的情況

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
const int N=4000009;
int T;
ll p[N],p1[N];
ll qpow(ll a, ll b){
    ll res=1;
    a%=mod;
    while(b){
        if(b&1)
            res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll cal(ll a,ll b){
    if(a<0||b<0||a-b<0)//不合法
        return 0;
    return p[a]*p1[b]%mod*p1[a-b]%mod;
}
int main() {
    p[0]=1;
    for(int i=1;i<N;i++)
        p[i]=p[i-1]*i%mod;
    p1[N-1]=qpow(p[N-1],mod-2);
    for(int i=N-2;i>=0;i--)
    p1[i]=p1[i+1]*(i+1)%mod;
    cin>>T;
    while(T--){
        ll n,m,k,tmp,tmp1;
        cin>>n>>m>>k;
        tmp=cal(2*m-1-k,m-1)*k%mod*qpow(m,mod-2)%mod;
        tmp1=cal(2*n-2*m+k,n-m)*(k+1)%mod*qpow(n-m+k+1,mod-2)%mod;
        cout<<tmp*tmp1%mod<<endl;
    }
    return 0;
}

相關文章