AGC030F
给定 (N),现在有一个长度为 (2N) 的序列 (A),其构成一个 (1sim 2N) 的排列,部分位置的值已经给出。
令 (B_i=min (A_{2i-1},A_{2i}))
求可能的 (B) 序列的数量,答案对 (10^9+7) 取模。
(Nle 300)
Solution
思维好题。
假设 (A_{2i-1},A_{2i}) 确定了,那么 (B_i) 确定了。
我们可以将两个值删去。
否则假设只确定了一个,相当于说明 (B_ile x),我们再 (x) 处进行标记
从值域上考虑,我们发现问题等价于选择一些点作为 (min),然后将这些 (min) 和 (B) 数组进行配对,求合法的方案数。
由于后面位置的限制较松,考虑从后往前 Dp,设 (f_{i,j,k}) 表示考虑到权值 (i),当前有 (j) 个普通位置需要往前匹配,(k) 个限制 (B) 需要往前匹配的方案数。
当然,由于没有匹配限制 (B) 的 (min) 节点还需要匹配其余的 (B) 序列,所以答案需要乘以 ((n-m)!)
转移是 naive 的,复杂度为 (O(N^3))
启示:对于 Dp 进行考虑的时候,可以对限制和规则进行观察,有的时候从后往前 Dp 即可解决问题,例如 AGC012F 和 AGC030F
(Code:)
#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 P = 1e9 + 7 ;
const int N = 300 + 5 ;
int n, m, D, A[N * 2], d[N * 2], L[N * 2] ;
int dp[N * 2][N * 2][N], f[N][N] ;
void inc(int &x, int y) {
((x += y) >= P) && (x -= P) ;
}
signed main()
{
n = gi(), m = n * 2, D = n ;
rep( i, 1, m ) A[i] = gi() ;
for(re int i = 1; i < m; i += 2 ) {
int u = A[i], v = A[i + 1] ;
if( u < 0 && v < 0 ) continue ;
if( u > 0 && v > 0 ) -- D, d[u] = 1, d[v] = 1 ;
else u = max( u, v ), L[u] = 1, -- D ;
}
dp[m + 1][0][0] = 1 ;
for(re int i = m; i >= 1; -- i) {
if(d[i])
rep( j, 0, m ) rep( k, 0, n ) dp[i][j][k] = dp[i + 1][j][k] ;
else if( L[i] )
rep( j, 0, m ) rep( k, 0, n )
inc( dp[i][j][k], dp[i + 1][j + 1][k] ),
inc( dp[i][j][k + 1], dp[i + 1][j][k] ) ;
else
rep( j, 0, m ) rep( k, 0, n )
inc( dp[i][j][k], dp[i + 1][j][k + 1] * (k + 1) % P ),
inc( dp[i][j + 1][k], dp[i + 1][j][k] ),
inc( dp[i][j][k], dp[i + 1][j + 1][k] ) ;
}
int ans = dp[1][0][0] ;
rep( i, 1, D ) ans = ans * i % P ;
cout << ans << endl ;
return 0 ;
}