「ABC217F」Make Pair 的题解

题目大意

一共 \(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;
}
posted @ 2024-07-14 13:38  未抑郁的刘大狗  阅读(4)  评论(0编辑  收藏  举报