考虑当前还没有被取出来的 \(Y\) 集合中最大的数 \(x\),显然我们只需要保证任意时刻加入堆中的非 \(Y\) 元素大于 \(x\)

\(x\) 的图像一定是逐渐变小的,我们每一次加入非 \(Y\) 元素时,能选择的范围也在逐步扩大。

经典问题:

我们需要选择一个排列 \(P\),要求 \(1\leq P_i \leq a_i\),其中 \(a_i\) 满足单调不降,求排列的数量。

我们从第一个下标开始决定填什么数,那么显然前面填的数一定在后面的可选范围之中,所以答案就是 \(\prod \limits_{i=1}^n (a_i-i+1)\),也就是每一个数的选择范围减去之前选择了的数量。

那么我们现在的问题就是如何记录 \(Y\) 集合中已经在堆中的元素最大值,由于有删除操作,这个东西变得非常棘手,在 \(M\leq 12\) 的时候可以考虑状压 \(dp\)

\(M\) 更大的时候我们显然是不能记录这个堆中具体有哪些元素了。我们注意到,每一次都是取出的最小值,如果最大值发生变化了,那么一定满足 最大值已经加入了堆中,且 \(Y\) 集合中所有加入堆的元素已经被取出来

我们有一个经典思路,对于 \(Y\) 集合中的元素,我们只钦定他们的位置,而不确定他们的具体值,在最大值发生变化的时候再来决定。

具体的讲,我们设 \(f_{i,j,k,l}\) 表示,已经考虑了前 \(i\) 个元素,还没有加入堆中的 \(Y\) 集合元素最大值为 \(a_j\)\(a\) 就是 \(Y\) 集合中的元素从小到大排序后的数组),堆的大小为 \(k\)\(j\) 是否在堆里面(\(l\))。


每一次转移需要考虑下一个是什么符号,如果是 +

  • 加入了非 \(Y\) 集合中的元素,根据前面的分析,有 \(f_{i,j,k,l}\times ((n-a_j)-(m-j)-(push_i-pop_i-k))\rightarrow f_{i+1,j,k,l}\)

\(push_i\) 的意思是在 \(i\) 之前 + 的数量。

\((n-a_j)-(m-j)\) 是比 \(a_j\) 大的非 \(Y\) 集合中的元素个数。

\(push_i-pop_i-k\) 是在前面已经放了多少个非 \(Y\) 集合的元素,就是所有放的元素个数减去已经放了的 \(Y\) 集合中的元素个数。

  • 加入了 \(Y\) 集合中的元素

有两种可能,第一种是加入了 \(a_j\),第二种是加入了其他在 \(Y\) 中的数。

在第一种情况下,我们已经确定这个数了,转移系数为 \(1\)

在第二种情况下,我们已经确定这个数的位置了,但是我们现在还不决定他是什么数,转移系数为 \(1\)


如果下一个符号是 -

考虑什么时候最大值会变?那一定是把最大值从堆中取出来了,此时一定满足 \(k=1,l=1\)

\(k\neq 1\)\(l\neq 1\),有 \(f_{i,j,k,l}\rightarrow f_{i+1,j,k-1,l}\)

\(k=1\)\(l=1\),此时我们枚举下一个最大值是 \(j'\),如果想要最大值变成 \(j’\),那么 \((j',j)\) 中的数必然已经被删除了。此时 \(k=1\),前面的 +- 已经一一匹配,我们在前面添加的数中找 \(j-j'-1\) 个位置放 \((j',j)\),很显然他们的相对位置不会影响最大值的变化,所以再乘上 \((j-j'-1)!\)

#include<bits/stdc++.h> 
using namespace std;
#define N 305
#define p 998244353
#define ll long long
char s[N];
int n,m,a[N<<1],prd[N<<1],pra[N<<1];
ll f[N<<1][N][N][2],fac[N],inv[N],pinv[N];//前 i 个数 
inline void upd(ll &x,ll y){(x+=y)%=p;}
inline ll C(int n,int m){return n<m?0:fac[n]*pinv[n-m]%p*pinv[m]%p;}
int main(){
	fac[0]=fac[1]=inv[0]=inv[1]=pinv[0]=pinv[1]=1;
	for(int i=2;i<N;i++)fac[i]=fac[i-1]*i%p,inv[i]=inv[p%i]*(p-p/i)%p,pinv[i]=pinv[i-1]*inv[i]%p;
	scanf("%d%d%s",&n,&m,s+1);
	for(int i=1;i<=n+m;i++)prd[i]=prd[i-1]+(s[i]=='-'),pra[i]=pra[i-1]+(s[i]=='+');
	for(int i=1;i<=m;i++)scanf("%d",&a[i]);
	f[0][m][0][0]=1;
	for(int i=0;i<=n+m;i++)for(int j=0;j<=m;j++)for(int k=0;k<=m;k++)for(int l=0;l<2;l++)if(f[i][j][k][l]){
		if(s[i+1]=='+'){
			upd(f[i+1][j][k+1][l],f[i][j][k][l]);//Y,! j
			if(!l)upd(f[i+1][j][k+1][1],f[i][j][k][l]);//Y j
			upd(f[i+1][j][k][l],f[i][j][k][l]*(n-a[j]-(m-j)-(pra[i]-prd[i]-k))%p);//!Y
		}
		else if(k){
			if(k>1||l==0)
				upd(f[i+1][j][k-1][l],f[i][j][k][l]);
			else for(int tj=0;tj<j;tj++)
				upd(f[i+1][tj][0][0],f[i][j][k][l]*C(prd[i]-(m-j),j-tj-1)%p*fac[j-tj-1]%p);
		}
	}
	printf("%lld",f[n+m][0][0][0]);
}