AGC030F

AGC030F

给定 \(N\),现在有一个长度为 \(2N\) 的序列 \(A\),其构成一个 \(1\sim 2N\) 的排列,部分位置的值已经给出。

\(B_i=\min (A_{2i-1},A_{2i})\)

求可能的 \(B\) 序列的数量,答案对 \(10^9+7\) 取模。

\(N\le 300\)

Solution

思维好题。

假设 \(A_{2i-1},A_{2i}\) 确定了,那么 \(B_i\) 确定了。

我们可以将两个值删去。

否则假设只确定了一个,相当于说明 \(B_i\le 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 ;
}

posted @ 2020-10-04 20:18  Soulist  阅读(172)  评论(0)    收藏  举报