题目大意
一共 \(2N\) 个学生站成一排,其中有 \(M\) 对朋友关系。老师每次从队列中挑出两个相邻的学生作为同桌。为了关系和睦,每次选出的两个学生必须是朋友关系。选出的两个学生离开队列,空出来的位置左右合拢。
请问老师有多少种方式选完所有学生?对于两种选人的方案,即使同桌关系相同,只要离开队列的顺序不同,也算是不同的方案,其中 \(1\le n\le 200\)。
思路
定义 \(f_{l,r}\) 表示将区间 \([l,r]\) 全部消除的方案数。
考虑 \(r\) 与上一个区间的哪一个数配对:
-
如果 \(l,r\) 组合在一起,那么首先因该消除区间 \([l+1,r-1]\),转移方程为 \(f_{l,r}=f_{l+1,r-1}\)。
-
如果 \(k,r\) 组合在一起,那么将这个大区间拆分为两个小区间 \([l,k-1]\) 和 \([k+1,r]\)。因为两个区间是相对独立的,两个物件互不影响。那么如果左侧有 \(x\) 种方案,右侧有 \(y\) 种方案,那么总方案为 \(x\times y \times C_{\frac{r-l+1}{2}}^{\frac{r-k+1}{2}}\)。
AC Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=405,mod=998244353;
int n,m,inv[N],jc[N],f[N][N];
bool a[N][N];
int ksm(int a,int b){
int ans=1;
while(b){
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}return ans;
}
void init(){
inv[0]=jc[0]=1;
for(int i=1;i<N;i++){
jc[i]=(jc[i-1]*i)%mod;
inv[i]=ksm(jc[i],mod-2);
}
}
int c(int n,int m){
return ((jc[n]*inv[m])%mod*inv[n-m])%mod;
}
signed main(){
init();
cin>>n>>m;
for(int i=1,x,y;i<=m;i++){
cin>>x>>y;
a[x][y]=a[y][x]=1;
if(abs(x-y)==1) f[x][y]=f[y][x]=1;
}
n*=2;
for(int len=3;len<n;len+=2){
for(int l=1;l+len<=n;l++){
int r=l+len;
if(a[l][r]) f[l][r]=f[l+1][r-1];
for(int k=l+2;k<r;k+=2){
if(a[k][r]) f[l][r]=(f[l][r]+(f[l][k-1]*f[k+1][r-1])%mod*c(len/2+1,(r-k+1)/2))%mod;
}
}
}
cout<<f[1][n];
return 0;
}
标签:方案,int,题解,Make,学生,区间,ans,Pair,mod
From: https://www.cnblogs.com/liudagou/p/18301431