Prefix Median
首先我们可以发现一个很显然的性质,\(b_n\)是确定的,等于\(a\)的中位数。
为了方便讨论,我们先将排个序。
由此,我们继续讨论\(b_{n-1}\)的情况,相较于\(b_n\),我们发现我们需要在所有的\(n\)中删去两个数,可能是在\(b_n\)的左右或是它自己,无论如何我们都可以发现,他们在\(a\)中的位置不会超过\(1\)。
推广得到,\(b_i\)不会与\(b_{i+1}\)在\(a\)中的位置超过\(1\)。
所以我们可以得到两个性质:
性质1:对于任意\(i < j\) 不会 存在\(b_j < b_i < b_{j+1}\) 或者 \(b_{j+1} < b_i < b_{j}\)
性质2:\(a_i \leq b_i \leq a_{2 \times n - i}\)
所以对于一个\(b_i\)的取值范围很显然就是\([a_i , \min(b_j)]\)和\([\max(b_j) , a_{2 \times n - i}]\)。
所以我们定义\(dp[i][L][R]\)表示确定\(b_i\)后,在上述1号区间有\(L\)个取法,2号区间\(R\)种取法的方案数。
dp就很好转移了,我们只需要暴力枚举一组\(dp_{i+1,l,r}\),然后暴力枚举我们钦定的\(b_i\),同时确定钦定的\(b_i\)的\(L\)和\(R\)就可以了。
最后注意一下细节,因为我们可能会有重复的数,而重复的数不能重复去钦定,所以需要特殊判断一下,具体判断方式见代码。
#include <cstdio>
#include <algorithm>
using namespace std;
const int mod = 1e9 + 7;
int dp[105][105][105] , n , a[105];
int main() {
scanf("%d" , &n);
for (int i = 1; i <= 2 * n - 1; ++i) scanf("%d" , &a[i]);
sort(a + 1 , a + 1 + 2 * n - 1);
dp[n][1][0] = 1;
for (int i = n - 1; i >= 1; --i) {
int lf = (a[i] != a[i + 1]) , rf = (a[2 * n - i] != a[2 * n - i - 1]); //判重,重复则不能扩展到我们的备选区间种
for (int l = 0; l <= 2 * n - 1; ++l) {
for (int r = 0; r <= 2 * n - 1; ++r) {
if(dp[i + 1][l][r]) {
int t = dp[i + 1][l][r];
for (int dl = 1; dl <= l + lf; ++dl) dp[i][l + lf - dl + 1][r + rf + (dl > 1)] += t , dp[i][l + lf - dl + 1][r + rf + (dl > 1)] %= mod;
for (int dr = 1; dr <= r + rf; ++dr) dp[i][l + lf + 1][r + rf - dr] += t , dp[i][l + lf + 1][r + rf - dr] %= mod;
}
}
}
}
long long ans = 0;
for (int l = 0; l <= 2 * n - 1; ++l) {
for (int r = 0; r <= 2 * n - 1; ++r) {
ans = (ans + dp[1][l][r]) % mod;
}
}
printf("%lld" , ans);
return 0;
}