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;
}
posted @ 2020-08-03 17:43  Reanap  阅读(91)  评论(0编辑  收藏  举报