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;
}

浙公网安备 33010602011771号