AT_abc217_f

思路

我们可以发现这一定是一个区间 Dp,那么我们定义 \(f_{l,r}\) 为消掉 \(l\sim r\) 的最小操作次数,那么我们就可以枚举一个区间长度以及左端点。然后我们如果枚举的左右端点可以消掉,那么 \(f_{a,b}=f_{a+1,b-1}\) 即将中间消掉的代价。

然后我们可以枚举一个中间点 \(k\),如果它能和 \(b\) 匹配上,即可使用和上面一样的方法,然后再将 \(f_{a,k-1}\) 的方案数乘上,最后因为要求的是方案数所以可以调换顺序,那么再乘上一个 \(\tbinom{l\div 2}{(k-b+1)\div 2}\) 即可。

注意这里的 \(l\)\(k\) 必须是偶数。

代码

#include <bits/stdc++.h>
#define IOS std::ios::sync_with_stdio(fasle);cin.tie(NULL);cout.tie(NULL)
#define int long long
#define ri register int
#define rep(i,x,y) for(ri i=x;i<=y;i++)
#define rep1(i,x,y) for(ri i=x;i>=y;i--)
#define il inline
#define fire signed
#define pai(a,x,y) sort(a+x,a+y+1)
using namespace std ;
il int qmi(int a,int b) {
	int res=1;
	while(b) {
		if(b&1) res=(res*a);
		a=a*a;
		b>>=1;
	}
	return res;
}
void print(int x) {
	if(x>=10) print(x/10);
	putchar(x%10+'0');
}
#define gcd(x,y) __gcd(x,y)
#define lcm(x,y) x*y/gcd(x,y)
int n,m;
const int N=501;
int mp[N][N];
int f[N][N];
int c[455][455];
const int mod=998244353;
fire main() {
	cin>>n>>m;
	rep(i,1,m) {
		int a,b;
		cin>>a>>b;
		if((a-b+1)%2==0) {
			mp[a][b]=1;
			if(a+1==b||b+1==a) f[a][b]=f[b][a]=1;
		}
	}
	rep(i,0,450-1) {
		rep(j,0,i) {
			if(!i) c[i][j]=1;
			else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
		}
	}
	rep(l,2,2*n) {
		rep(a,1,2*n+1-l) {
			int b=a+l-1;
			if(mp[a][b]) f[a][b]=f[a+1][b-1];
			rep(k,a+2,b-1) {
				if(mp[k][b]) {
					f[a][b]=(f[a][b]+f[a][k-1]*f[k+1][b-1]%mod*c[l/2][(b-k+1)/2]%mod)%mod;
				}else if(mp[a][k]) f[a][b]=(f[a][b]+f[a+1][k-1]*f[k+1][b]%mod*c[l/2][(k-a+1)/2]%mod)%mod;
				k+=1;
			}
		}
		l++;
	}
	cout<<f[1][2*n]<<endl;
	return false;
}

posted @ 2024-01-31 11:52  highkj  阅读(7)  评论(0)    收藏  举报