CF1924D Balanced Subsequences 题解

题目链接

点击打开链接

题目解法

呜呜呜,几天不做题,啥题都不会了/ll

考虑删除匹配括号后的序列形如:\()...)(...(\)
其中有 \(a=m-k\)\()\)\(b=n-k\)\((\)
考虑在其中插入 \(k\) 对匹配括号
假设有 \(x\) 对匹配括号插入到 \()...)\) 中,对于 \(k-x\) 对匹配括号插入到 \((...(\) 类似,需要注意为了不算重,我们钦定后者的括号序列的首位为 \((\)

括号序列的问题最常见的方法就是画出折线图
\((\) 为右上,\()\) 为右下
则为起始点为 \((0,0)\),终止点为 \((a+2x,-a)\),且不能经过 \(y=-a-1\) 的方案数
不难通过经典的折线图容斥得到答案为 \(\binom{a+2x}{x}-\binom{a+2x}{x-1}\)

时间复杂度为 \(O(n+m+\sum k)\)

#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
inline int read(){
    int FF=0,RR=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
    for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
    return FF*RR;
}
const int N=4010,P=1e9+7;
int fac[N],ifac[N];
int qmi(int a,int b){
    int res=1;
    for(;b;b>>=1){ if(b&1) res=1ll*res*a%P;a=1ll*a*a%P;}
    return res;
}
void comb(int n){
    fac[0]=1;F(i,1,n) fac[i]=1ll*fac[i-1]*i%P;
    ifac[n]=qmi(fac[n],P-2);DF(i,n-1,0) ifac[i]=1ll*ifac[i+1]*(i+1)%P;
}
int bin(int x,int y){ if(x<y||y<0) return 0;return 1ll*fac[x]*ifac[y]%P*ifac[x-y]%P;}
int calc(int x,int y){ return (bin(x,y)-bin(x,y-1)+P)%P;}
void work(){
    int n=read(),m=read(),k=read();
    int a=m-k,b=n-k;
    if(a<0||b<0){ puts("0");return;}
    if(!a&&!b){ printf("%lld\n",1ll*bin(2*n,n)*ifac[n+1]%P*fac[n]%P);return;}
    if(!b) swap(a,b);
    int ans=0;
    F(i,0,k){
        int j=k-i;
        int coef=1ll*calc(a+2*i,i)*calc(b+2*j-1,j)%P;
        ans=(ans+coef)%P;
    }
    printf("%d\n",ans);
}
int main(){
    comb(N-1);
    int T=read();
    while(T--) work();    
    return 0;
}

posted @ 2024-02-17 16:11  Farmer_D  阅读(25)  评论(0)    收藏  举报