「ABC217F」Make Pair Tj
题意
一共个学生站成一排,其中有
对朋友关系。老师每次从队列中挑出两个相邻的学生作为同桌。为了关系和睦,每次选出的两个学生必须是朋友关系。选出的两个学生离开队列,空出来的位置左右合拢。
请问老师有多少种方式选完所有学生?对于两种选人的方案,即使同桌关系相同,只要离开队列的顺序不同,也算是不同的方案。
思路
dp做。
状态设计:
设dp[l][r]表示删除区间[l,r]的总方案数。
状态转移
考虑r和谁一起删掉
+ 和
一起删,那么区间
必须先删完:
+ 和
一起删,那么就要删掉
,
,两个区间互不影响。若区间
的方案数为
,
方案数为
:
细节处理
输入的时候
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>x>>y;
//因为是两个两个取,所以相隔距离为奇数的不可能成为同桌 (请自行举例)
if((y-x+1)%2==0){
vis[x][y]=1;
if(x+1==y||y+1==x)
dp[x][y]=dp[y][x]=1;
}
}
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int n,m,x,y;
int C[500][500],vis[500][500],dp[500][500];
void init(){//杨辉三角求组合数:C[m][n]=C[m-1][n-1]+C[m][n-1]
//O(n^2)
for(int i=0;i<=n;i++){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
}
signed main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>x>>y;
//因为是两个两个取,所以相隔距离为奇数的不可能成为同桌
if((y-x+1)%2==0){
vis[x][y]=1;
if(x+1==y||y+1==x)
dp[x][y]=dp[y][x]=1;
}
}
init();//预处理组合数
for(int len=2;len<=2*n;len+=2){
for(int l=1;l+len-1<=n*2;l++){
int r=l+len-1;
if(vis[l][r])
dp[l][r]=dp[l+1][r-1];
//禁止写成:
// for(int k=l;k<=r;k++)
//emm...我就是这里错了
for(int k=l+2;k<r;k+=2){
//
if(vis[k][r])//
dp[l][r]=(dp[l][r]+dp[l][k-1]*dp[k+1][r-1]%mod*C[len/2][(r-k+1)/2]%mod+mod)%mod;
}
}
}
cout<<dp[1][n*2];
return 0;
}