首页 > 其他分享 >Chests and Keys 题解

Chests and Keys 题解

时间:2024-03-06 15:24:43浏览次数:29  
标签:宝箱 int 题解 Alice times Chests Keys Bob rightarrow

题意:

给定 \(n,m\) 表示存在 \(n\) 个宝箱和 \(m\) 把钥匙,第 \(i\) 把钥匙需要 \(b_i\) 元,第 \(i\) 个宝箱内部有 \(a_i\) 元。

现在进行一场游戏,Bob 是本场游戏的玩家,而 Alice 则是场景布置者,Alice 可以给每个宝箱上一些锁(第 \(j\) 种锁需要第 \(j\) 种钥匙打开)

如果 Bob 可以购买一些钥匙,然后打开一些宝箱,使得 Bob 的收益大于 \(0\),那么 Bob 就赢得了游戏,反之 Alice 获得了胜利。

现在 Alice 打算布置宝箱上的锁,第 \(i\) 个宝箱上放置第 \(j\) 种锁的花费为 \(c_{i,j}\),请帮助 Alice 找到一种布置锁的方案,使得花费最小,且 Alice 将取得胜利。

\(n,m\le 6,a_i,b_i\le 4,c_{i,j}\le 10^7\)

特别的,一个箱子上可以放置若干把锁,Bob 需打开所有锁才能获得内部的钱。

分析:

先考虑如果给定了所有宝箱的布置锁的方案求 Bob 所得到的最大利益。

考虑网络流,连边 \(S \rightarrow i(w=a_{i}),\ i \rightarrow j(w=+\infty),\ j \rightarrow T(w=b_{j})\),其中 \(i\) 表示箱子,\(j\) 表示锁。那么最大利益即为 \((\sum a_{i})-Mincut\),具体证明见 P2762 太空飞行计划问题

这题显然不能枚举所有所有宝箱的布置锁的方案,那怎么做呢?

如果想要 Bob 获利为 \(0\),即必须让他割 \(S\) 到所有箱子的边。

这题的突破口在于网络中的最大流量应使 \(S\) 到所有箱子的边达到满流,否则最小割一定不是 \(S\) 到所有箱子的边。

知道了这点就很简单了,注意到 \(a_{i},b_{i} \le 4\),随便 dp 一下即可。

比如我们可以记 \(f_{i,j,k,l}\) 表示考虑到第 \(i\) 个箱子(该箱子残余流量为 \(l\)),此时所有钥匙的残余流量集合为 \(j\),目前在考虑是否要走 \(i \rightarrow k\) 这条边。

状态数是 \(6 \times 5^6 \times 6 \times 4=2.5 \times 10^5\),不会爆空间。

需要注意的是考虑是否要走 \(i \rightarrow k\) 这条边时,我们还需要枚举其流量,不能无脑全流。

时间复杂度为 \(O(nmw^2 \times (w+1)^m)\)。

代码:

#include<bits/stdc++.h>
#define int long long
#define N 10
using namespace std;
int n, m, ans = 1e18;
int a[N], b[N], c[N][N], cnt;
vector<int>now, z, p[100005], r;
int f[8][16000][7][7];
map<vector<int>, int>num;
void dfs(int k) {
	if(k > m) {
		p[++cnt] = z;
		num[z] = cnt;
		for(int i = 1; i <= n + 1; i++)
		for(int j = 1; j <= m; j++)
		for(int l = 0; l <= 4; l++)
			f[i][cnt][j][l] = 1e18;
		return;
	}
	for(int i = 0; i <= b[k]; i++) {
		z.push_back(i);
		dfs(k + 1);
		z.pop_back();
	}
}
void upd(int &x, int y) {
	x = min(x, y);
}
signed main() {
	cin >> n >> m;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= m; i++) cin >> b[i], now.push_back(b[i]);
	for(int i = 1; i <= n; i++)
	for(int j = 1; j <= m; j++) cin >> c[i][j];
	dfs(1);
	f[1][num[now]][1][a[1]] = 0;
	for(int i = 1; i <= n; i++) {
		for(int k = 1; k <= m; k++) {
			for(int j = 1; j <= cnt; j++) {
				for(int l = 0; l <= a[i]; l++) {
					if(k != m) {
						upd(f[i][j][k + 1][l], f[i][j][k][l]);
						int use = min(l, p[j][k - 1]);
						r = p[j];
						for(int v = 1; v <= use; v++) {
							r[k - 1] -= v;
							upd(f[i][num[r]][k + 1][l - v], f[i][j][k][l] + c[i][k]);
							r[k - 1] += v;
						}
					}
					else {
						if(l == 0) upd(f[i + 1][j][1][a[i + 1]], f[i][j][k][l]);
						else if(p[j][k - 1] >= l) {
							r = p[j];
							r[k - 1] -= l;
							upd(f[i + 1][num[r]][1][a[i + 1]], f[i][j][k][l] + c[i][k]);
						}
					}
				}
			}
		}
	}
	for(int i = 1; i <= cnt; i++) ans = min(ans, f[n + 1][i][1][0]);
	if(ans == 1e18) cout << -1;
	else cout << ans;
	return 0;
}

标签:宝箱,int,题解,Alice,times,Chests,Keys,Bob,rightarrow
From: https://www.cnblogs.com/xcs123/p/18056677

相关文章

  • Linux使用问题之长时间连接ssh不操作自动断开问题解决方案
    1.概要一般情况下,在使用SSHSecureShellClient的过程中,经常会遇到当用SSHSecureShell连接登录Linux后,如果几分钟没有任何操作,连接就会自动断开,提示Serverresponded"Connectionclosed.",必须重新登录才可以。2.原理主要由以下两个参数控制:ClientAliveInterval:指定了服......
  • springboot 应用程序 pom节点版本冲突问题解决思路
    springboot应用程序pom节点版本冲突问题解决思路一、首先 mavenhelper 查看是否有冲突 conflicts 二、allDenpendencies  查询如poi 查询冲突 ps: <scope>compile</scope>  compile:这是默认的依赖项范围。指定为compile的依赖项将在编译、测试和......
  • [AGC016D] XOR Replace 题解
    题意:一个序列\(a\),一次操作可以将某个位置变成整个序列的异或和。求最少几步到达目标序列\(b\)。\(n\le10^5\)思路:见到这种题,第一步要去尝试把操作转化。稍微推一下可以发现,如果\(\oplus_{i=1}^na_i=s\),则相当于一个\(n+1\)长序列,\(a_{n+1}=s\),每次可以交换\(a......
  • 九省联考题解第一弹(1-8)
    2024九省联考题解样本数据16,24,14,10,20,30,12,14,40的中位数为?解:排序后为10,12,14,14,16,20,24,30,40,答案显然为16。椭圆\(\frac{x^2}{a^2}+y^2=1(a>1)\)的离心率为\(\frac{1}{2}\),求\(a\)。解:直接上椭圆基础公式。在题干中\(b=1\),离心率\(e=\frac{c}{a}=\frac{\sqrt{a^2-b^2}}{a}=\fr......
  • CF1925D Good Trip 题解
    Solution不好做的地方在于每一对朋友的友谊值是不同的,于是考虑将其统一为一个数。比较好想的就是将他们的初始友谊值提前计算,即对于每一次远足,设总情况为\(S=\frac{n\times(n-1)}{2}\),总的初始友谊值为\(w=\sum_{i=1}^{m}f_i\),假设友谊值不变,获得的期望友谊值为\(\frac{w}{......
  • ABC259Ex 题解
    Solution首先考虑暴力:枚举同种颜色的格子,假设两点为\((i,j),(x,y)\),那么从\((i,j)\)到\((x,y)\)的方案数即为\(C_{x-i+y-j}^{x-i}\)。考虑当前颜色有\(B\)个,枚举的时间复杂度为\(O(B^2)\)。考虑枚举每一种颜色,算出这种颜色到其他格子方案数,有递推方程:\(f_{i,j}=f_......
  • CF1800F 题解
    Solution考虑转化题目条件,因为要求字符串恰好有\(25\)个字符,所以考虑枚举没出现过的字符,令其为\(k\)。再令\(f_{i,p}\)表示第\(i\)个字符串\(p\)字符出现次数的奇偶,于是题目条件即为:\(f_{i,k}=f_{j,k}=0\)。\(f_{i,p}+f_{j,p}\bmod2=1\)。于是考虑用一个\(2^{26......
  • CF622F The Sum of the k-th Powers 题解
    原式为\(k+1\)次多项式,所以需要\(k+2\)个点确定。然后转化,前缀和。\[\begin{equation}n=k+2\\\end{equation}\]\[\begin{equation}f(x)=\sum\limits_{i=0}^{n}y_i\prod\limits_{j=0,j\nei}^{n}\frac{x-x_j}{x_i-x_j}\end{equation}\]\[\begin{equation}x_0=......
  • AT_abc331_f [ABC331F] Palindrome Query 题解
    分析线段树。每个节点维护两个值:$s[l\dotsr]$和$s[r\dotsl]$。判断字串是否是回文直接就是询问的答案维护出来的两个值是否相同。首先想到用线段树暴力维护。第一个值很显然是两个儿子的第一个值加起来,第二个值是反着加起来。得到很酷的代码:ilvoidup(intnow){ tr[now......
  • AT_abc287_g [ABC287G] Balance Update Query 题解
    分析一眼分块。用值域分块来维护。先把所有的值离散化,使得至于不大于$n+q$。统计一下每个值的数量,每个块包含值的数量,每个块的价值和。修改值的时候先把原来值的数量,块包含的数量,块的价值剪掉被修改值的贡献,然后在新的值上面更新。修改数量直接改数量的变化贡献即可。找前$x$......