题解 AT2366 【[AGC012F] Prefix Median】
题意
给定
- 随机打乱排列
a - 令
p_i=\{a_1,a_2..a_{2i-1}\} 中的中位数
不妨先考虑怎么样的一个序列
我们将原问题视为,初始有一个数
接下来每次选取
于是我们可以发现,如果每次加入的两个数比
同时,我们如果对于序列
反过来思考,我们发现
这个条件是一个必要条件,但不充分,我们发现一个
换而言之,假设考虑排列
这个条件配上之前的那个条件后充分吗?充分。
手玩可以比较感性的得到?
对于满足上述条件的
对于每个不同的
容易发现由于限制
于是我们的条件等价于:
-
a_i\le p_i\le a_{2n-i} -
p_i\in \{a_1,a_2...a_{2n-1}\} - 对于
i 和i+1 ,不存在j 满足p_i<p_j<p_{i+1} 或p_i>p_j>p_{i+1}
假设通过 dp 来进行计数,那么较为困难的就是限制
我们发现问题可以转换为:
初始有一个数
将
注意到,如果
由于移动有两种方向,实际上你会发现我们只关注在当前位置左边和右边两边分别的待选择的
于是令
#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define int long long
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < '0' || cc > '9' ) { if( cc == '-' ) flus = - flus ; cc = getchar() ; }
while( cc >= '0' && cc <= '9' ) cn = cn * 10 + cc - '0', cc = getchar() ;
return cn * flus ;
}
const int N = 100 + 5 ;
const int P = 1e9 + 7 ;
int n, a[N], dp[N][N][N] ;
signed main()
{
n = gi() ; int m = 2 * n ;
for( re int i = 1; i < m; ++ i ) a[i] = gi() ;
sort( a + 1, a + m ) ;
dp[n][0][0] = 1 ;
for( re int i = n - 1; i >= 1; -- i ) {
int dl = ( a[i] != a[i + 1] ), dr = ( a[m - i] != a[m - i - 1] ) ;
rep( l, 0, m ) {
rep( r, 0, m ) {
dp[i][l + dl][r + dr] = ( dp[i][l + dl][r + dr] + dp[i + 1][l][r] ) % P ;
for( re int k = 0; k < l + dl; ++ k )
dp[i][k][r + 1 + dr] = ( dp[i][k][r + 1 + dr] + dp[i + 1][l][r] ) % P ;
for( re int k = 0; k < r + dr; ++ k )
dp[i][l + 1 + dl][k] = ( dp[i][l + dl + 1][k] + dp[i + 1][l][r] ) % P ;
}
}
}
int Ans = 0 ;
rep( l, 0, m ) rep( r, 0, m ) Ans = ( Ans + dp[1][l][r] ) % P ;
cout << Ans << endl ;
return 0 ;
}