[abc313 h/ex] Group Photo

发布时间 2023-10-10 16:12:17作者: LuoyuSitfitw

Ex - Group Photo

很牛的题

\(A_0=A_{n+1}=INF\),那么对于每个\(B_i\)\(B_i>\min(A_{i-1},A_i)\),所以考虑设\(C_i\)表示\(min(A_{i-1},A_i)\),那么有\(B_i>C_i\),显然,若我们将\(C\)从小到大排序,\(B\)也从小到大排序,那么肯定是一一对应的(即满足\(B_i>C_i\)时合法)

考虑\(C_i=A_i\)时,说明若我们将\(A\)也从小到大排序后挨个放入序列中,有\(A_i\)\(A_{i-1}\)先放入序列中,所以设\(dp[i][j]\)表示前\(i\)\(A\)放成了\(j\)个连通块

首先若我们放了了\(i\)\(A\),形成了\(j\)个连通块,那么一定有\(i+j\)\(C\)被确定并且一定是前\(i+j\)\(C\),那么前\(i+j\)\(C\)就一一对应了前\(i+j\)\(B\),所以考虑转移:

将第\(A_{i+1}\)放在每个块的首/尾,\(dp[i][j]\times2\times j\rightarrow dp[i+1][j](A_{i+1}<B_{i+j+1})\)

\(A_{i+1}\)链接两个连通块,\(dp[i][j]\times (j-1)\rightarrow dp[i+1][j-1]\),因为此时\(A_{i+1}\)两边的\(A\)都比\(A_{i+1}\)先加入,所以\(A_{i+1}\)不会产生新的\(C\)

\(A_{i+1}\)单独新建一个块,\(dp[i][j]\times(j+1)\rightarrow dp[i+1][j+1](A_{i+1}<B_{i+j+1}\&\&A_{i+1}<B_{i+j+2})\),因为\(B\)排了序,所以\(B_{i+j+1}<B_{i+j+2}\),所以只需要判断\(A_{i+1}<B_{i+j+1}\)

#include<bits/stdc++.h>
using namespace std;
const int N=5e3+5,MOD=998244353;
int dp[N][N],n,a[N],b[N]; 
void add(int &x,int y){ x+=y; (x>=MOD)&&(x-=MOD); (x<0)&&(x+=MOD); }
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	for(int i=1;i<=n+1;++i) scanf("%d",&b[i]);
	dp[0][0]=1,sort(a+1,a+n+1),sort(b+1,b+n+2);
	for(int i=0;i<n;++i){
		for(int j=0;j<=i&&i+j<=n+1;++j){
			if(a[i+1]<b[i+j+1]) add(dp[i+1][j],dp[i][j]*2ll%MOD*j%MOD);
			if(j>1) add(dp[i+1][j-1],1ll*dp[i][j]*(j-1)%MOD);
			if(a[i+1]<b[i+j+1]) add(dp[i+1][j+1],1ll*dp[i][j]*(j+1)%MOD);
		}
	}
	printf("%d",dp[n][1]);
	return 0;
}