CF1519F

水博客了。

先考虑确定宝箱之后怎么检查,可以 \(2^n\) 检查,然而是可以建立网络流的模型的,对于每个锁,连接宝箱 \(i\to\) 钥匙 \(j\) 的一条边,然后每个宝箱连接 \(S\) 流量 \(a_i\),每个钥匙连接 \(T\) 流量 \(b_i\)

可以发现如果最大流为 \(\sum a_i\) 那么就说明非法,这意味着左部满流。

发现流量非常小,我们考虑暴力一点来描述最大流:

给每条边指定流量,满足每个点流出为 \(a_i\)(均满流),然后检查流入序列 \(\{c\}\),如果对于任意 \(i\) 均有 \(c_i\le b_i\) 则合法,然后将所有流量非 \(0\) 的边加入答案。

我们考虑到 \(5^6=15625\),而每个点流出的方案又只有 \(\binom{9}{4}(\frac{1}{(1-x)^6}[x^4])=126\) 种,于是对此大力 dp 的复杂度是可以接受的。

总体复杂度 \(\mathcal O(\prod b_i(\sum \binom{a_i+m-1}{m}))\),我这里 DFS 转移的部分额外附带了一个 \(m\),大概是 \(\mathcal O(m\prod (b_i+1)(\sum \binom{a_i+m-1}{m}))\)

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( int i = (t); i >= (s); -- i )
#define mp make_pair
#define pi pair<int, int>
#define pb push_back
#define vi vector<int>
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 = 7 ; 
const int M = 2e4 + 5 ; 
const int inf = 4e8 ; 
vector<int> f[M] ; 
int n, m, fac[N], a[N], b[N], w[N][N], d[N], dp[N][M] ; 
void dfs(int x, int y, int c, int C) {
	if(x == m) {
		if(c > d[m]) return ; 
		int s = 0 ; d[m] -= c ; 
		rep( i, 1, m ) s += d[i] * fac[i] ; 
		dp[y][s] = min(dp[y][s], C + (c > 0) * w[y][m]) ; 
		d[m] += c ; 
		return ; 
	}
	rep( i, 0, min(d[x], c) ) {
		d[x] -= i ; 
		if(!i) dfs(x + 1, y, c, C) ;
		else dfs(x + 1, y, c - i, C + w[y][x]) ;
		d[x] += i ; 
	}
}
signed main()
{
	n = gi(), m = gi() ; 
	rep( i, 1, n ) a[i] = gi() ; 
	rep( i, 1, m ) b[i] = gi() ; 
	rep( i, 1, n ) rep( j, 1, m ) w[i][j] = gi() ; 
	fac[1] = 1 ; int S = 0 ; 
	rep( i, 2, m ) fac[i] = fac[i - 1] * (1 + b[i - 1]) ; 
	rep( i, 1, m ) S += fac[i] * b[i] ; 
	memset(dp, 63, sizeof(dp)), dp[0][S] = 0 ; 
	for(int x = 1; x <= n; ++ x) {
		rep( t, 0, S ) {
			int u = t ; 
			drep( i, 1, m ) d[i] = (u / fac[i]), u %= fac[i] ; 
			dfs(1, x, a[x], dp[x - 1][t]) ; 
		}
	}
	int ans = inf ; 
	rep( x, 0, S ) ans = min(ans, dp[n][x]) ;
	if(ans < inf) cout << ans << endl ; 
	else puts("-1") ; 
	return 0 ; 
}
posted @ 2021-05-03 14:35  Soulist  阅读(112)  评论(0编辑  收藏  举报