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 + 1})

性质2:(a_i leq b_i leq a_{2 imes n - i})

所以对于一个(b_i)的取值范围很显然就是([a_i ~ min(b_j)])([max(b_j) ~ a_{2 imes 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;
}
原文地址:https://www.cnblogs.com/Reanap/p/13427689.html