题目大意

一共 2N2N 个学生站成一排,其中有 MM 对朋友关系。老师每次从队列中挑出两个相邻的学生作为同桌。为了关系和睦,每次选出的两个学生必须是朋友关系。选出的两个学生离开队列,空出来的位置左右合拢。

请问老师有多少种方式选完所有学生?对于两种选人的方案,即使同桌关系相同,只要离开队列的顺序不同,也算是不同的方案,其中 1n2001\le n\le 200

思路

定义 fl,rf_{l,r} 表示将区间 [l,r][l,r] 全部消除的方案数。

考虑 rr 与上一个区间的哪一个数配对:

  • 如果 l,rl,r 组合在一起,那么首先因该消除区间 [l+1,r1][l+1,r-1],转移方程为 fl,r=fl+1,r1f_{l,r}=f_{l+1,r-1}

  • 如果 k,rk,r 组合在一起,那么将这个大区间拆分为两个小区间 [l,k1][l,k-1][k+1,r][k+1,r]。因为两个区间是相对独立的,两个物件互不影响。那么如果左侧有 xx 种方案,右侧有 yy 种方案,那么总方案为 x×y×Crl+12rk+12x\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;
}