链接

题意:

一共有ABC 217 F - Make Pair (区间DP)_#include个数,然后有m对好朋友,让你对其消消乐,使得他们好朋友好朋友之间配对,都能找到伴,问有多少中消法?

分析:

一共两种情况:

  • 两位朋友在两端,那么dp[i][j]=dp[i+1][j-1];
  • 一个朋友在一端®,另一个朋友在中间(l)。ABC 217 F - Make Pair (区间DP)_算法_02
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<ll,ll>
const int mod = 998244353;
const int maxn = 500;

ll qpow(ll a, ll b, ll p)
{
ll ans = 1;
while(b)
{
if(b & 1) ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans;
}
ll fac[maxn];
void init()
{
fac[0] = 1;
for(int i = 1; i < maxn; i++)
{
fac[i] = fac[i - 1] * i % mod;
}
}
ll infac(ll x)
{
return qpow(x, mod - 2, mod);
}
ll C(ll n, ll m)
{
if(n < m) return 0;
return fac[n] * infac(fac[m]) % mod * infac(fac[n - m]) % mod;
}

ll n, m;
bool flag[maxn][maxn];
ll dp[maxn][maxn];
std::vector<ll> v[maxn];
void solve()
{
cin >> n >> m;
for(int i = 1; i <= m; ++i)
{
ll x,y;
cin >> x >> y;
if((y-x-1)%2) continue;//中间有奇数个数 不用在考虑直接不用管
v[y].push_back(x);
}
for(int i=2;i<=2*n;i+=2){
for(int j=1;j<=2*n&&j+i-1<=2*n;j++){
for(auto it : v[j+i-1]){
if(it<j) continue;
int l=it+1;
int r=j+i-2;
if(l>r){
dp[l][r]=1;///能够到达
}
if(it==j){///左右端点一样
dp[j][j+i-1]+=dp[l][r];
dp[j][j+i-1]%=mod;
}
else {///不一样。
dp[j][i+j-1] += dp[j][it-1]*dp[l][r]%mod*C(i/2,(it-j)/2)%mod;
dp[j][i+j-1] %=mod;
}
}
}
}
cout<<dp[1][2*n]<<endl;
}

int main()
{
init();
int t = 1;
//scanf("%d",&t);
while(t--)
{
solve();
}
return 0;
}