Loading

【题解】ABC231G - Balls in Boxes & H - Minimum Coloring

G 想到一个非常神奇的做法。

如果我们令第 \(i\) 个位置放入了 \(b_i\) 个球,那么总代价一定是 \(\prod(a_i + b_i)\)

总方案数是 \(n^k\),我们只用求所有方案的代价之和。

对于一个代价,我们将它拆开,组合意义等价于选出一些 \(a_i\),剩下的选 \(b_i\),乘起来然后求和。

由于 \(a\) 是固定的,我们先简单 DP 一下求得 \(f_{n,i}\) 表示从 \(n\) 个数中,选出 \(i\) 个数的乘积的和,直接做是 \(\mathcal{O}(N^2)\) 已经足够了。

接下来我们枚举选出了 $x $ 个 \(b_i\),它们的和为 \(s(s\le k)\)

那么答案为 \(\sum\limits_{x = 0}^n f_{n, x}\sum\limits_{s = 0}^k \binom{k}{s}(n - x)^{k - s}g_{x, s}\)

其中 \(g_{n, k}\) 表示有 \(n\) 个空盒子,进行 \(k\) 次操作,所有情况的代价之和。

显然 \(g_{1, k} = k\)\(g_{n,k} = \sum\limits_{i = 0}^{k}i\binom{k}{i}g_{n - 1,k -i}\)。经过递推和组合恒等变换后可以求得 \(g_{n,k} = \dfrac{k!n^{k - n}}{(k - n)!}\)

(这个式子可以在变形后归纳证明,不知道有没有简单的组合意义解法

我们将这个式子带回去,可以求得 \(\sum\limits_{s = 0}^k \binom{k}{s}(n - x)^{k - s}g_{x, s} = \dfrac{k!n^{k - x}}{(k - x)!}\)

这式子可以直接 \(\mathcal{O}(N)\) 求,时间复杂度 \(\mathcal{O}(N^2)\)

#define N 1005
int n, a[N], f[N][N], k;
int g(int x){
	int cur = Pow(n, k - x);
	rep(i, 1, x)cur = 1LL * cur * (k - i + 1) % P;
	return cur;
}
int main(){
	n = read(), k = read();
	rep(i, 1, n)a[i] = read();
	f[0][0] = 1;
	rep(i, 1, n)rep(j, 0, n - 1)
		ad(f[i][j], f[i - 1][j]), ad(f[i][j + 1], f[i - 1][j] * 1LL * a[i] % P);
	int ans = 0;
	rep(i, 0, n)ad(ans, g(i) * 1LL * f[n][n - i] % P);
	ans = 1LL * ans * Pow(n, -k) % P;
	printf("%d\n", ans);
	return 0;
}

H 题很有意思,可惜没想出来。

显然这个个行列二分图模型,对于一个可以染色的格子对应一条权值为 \(c_i\) 的边,然后求二分图的带权最小边覆盖。

大家只知道最小边覆盖可以直接求最大匹配,考虑扩展到带权图。

对于最优情况,我们将选择的边扣出来,然后对这个边集的生成子图跑出最大匹配,显然不在匹配中的点,它也要被覆盖,它一定会选择相邻的最小的边去覆盖它。

所以对于每个点我们求相邻的边的最小值 \(v_i\),对于一个格子 \((a,b,c)\),连一条行 \(a\) 到列 \(b\), 权值为容量为 \(1\),权值为 \(v_a+v_b-c\) 的边,然后跑最大费用流即可。答案就是最大 \(\sum v - ans\)

注意这里的最大费用流是指费用最大的可行流而不是最大流,由于每条边容量最大为 \(1\),我们只增广代价为正的路径即可。

感觉这个模型非常类似反悔贪心,不知道能不能扩展。

#define N 2005
#define int long long
int n, m, T, a[N], b[N], c[N], h[N], tot = 1, u[N];
struct edge{int to, nxt, val, cap;}e[N << 5];
void add(int x,int y,int z,int val){
	e[++tot].nxt = h[x], h[x] = tot, e[tot].to = y, e[tot].cap = z, e[tot].val = val;
	e[++tot].nxt = h[y], h[y] = tot, e[tot].to = x, e[tot].cap = 0, e[tot].val = -val;
}
int flow[N], pre[N], d[N], v[N], s, t, ans;
queue<int>q;
bool bfs(){
	memset(d, 0xcf, sizeof(d));
	q.push(s), d[s] = flow[t] = 0, flow[s] = 1;
	while(!q.empty()){
		int x = q.front();
		q.pop(), v[x] = 0;
		for(int i = h[x]; i; i = e[i].nxt)if(e[i].cap && d[x] + e[i].val > d[e[i].to]){
			d[e[i].to] = d[x] + e[i].val, flow[e[i].to] = 1, pre[e[i].to] = i;
			v[e[i].to] = 1, q.push(e[i].to);
		}
	}
	return d[t] > 0;
}
void updata(){
	ans -= d[t];
	int x = t;
	while(x != s){
		e[pre[x]].cap --;
		e[pre[x] ^ 1].cap ++;
		x = e[pre[x] ^ 1].to;
	} 
}
signed main(){
	n = read(), m = read(), T = read();
	memset(u, 0x3f, sizeof(u));
	rp(i, T){
		a[i] = read(), b[i] = read(), c[i] = read();
		cmn(u[a[i]], c[i]), cmn(u[b[i] + n], c[i]);
	}
	s = n + m + 1, t = s + 1;
	rp(i, n)add(s, i, 1, 0);
	rp(i, m)add(i + n, t, 1, 0);
	rp(i, n + m)ans += u[i];
	rp(i, T)add(a[i], b[i] + n, 1, u[a[i]] + u[b[i] + n] - c[i]);
	while(bfs())updata();
	printf("%lld\n", ans);
	return 0;
}

posted @ 2021-12-16 16:55  7KByte  阅读(139)  评论(0编辑  收藏  举报