题解视频:牛客周赛round40,质量很高的一场周赛!背包不熟练同学的一定要补题!!!_哔哩哔哩_bilibili
题号 | 标题 | 已通过代码 | 通过率 | 我的状态 |
---|---|---|---|---|
A | 小红进地下城 | 点击查看 | 1419/1624 | 未通过 |
B | 小红打怪 | 点击查看 | 1266/2342 | 未通过 |
C | 小红的排列构造 | 点击查看 | 851/2591 | 未通过 |
D | 小红升装备 | 点击查看 | 387/2283 | 未通过 |
E | 小红的矩阵划分 | 点击查看 | 132/3143 | 未通过 |
F | 小红拿宝箱 | 点击查看 | 27/1097 | 未通过 |
C.小红的排列构造
#include<bits/stdc++.h>
using namespace std;
const int N = 202020;
int a[N],p[N],q[N];
int t1[N],t2[N];
int main(){
int n,i,j=1,j2=1;
int jud = 0;
cin>>n;
for(i=1;i<=n;i++){
cin>>a[i];
if(!t1[a[i]]) p[i] = a[i],t1[a[i]] = 1;
else if(!t2[a[i]]) q[i]=a[i],t2[a[i]] = 1;
else jud = 1;
}
if(jud) return cout<<-1,0;
for(i=1;i<=n;i++){
if(!p[i]){
while(t1[j]) j++;
p[i] = j;
t1[j] = 1;
}
if(!q[i]){
while(t2[j2]) j2++;
q[i] = j2;
t2[j2] = 1;
}
}
for(i=1;i<=n;i++) cout<<p[i]<<" ";
cout<<endl;
for(i=1;i<=n;i++) cout<<q[i]<<" ";
cout<<endl;
return 0;
}
模拟过程:
让我们通过一个具体的例子来解释上述代码的运行过程。假设输入的数组 \( n \) 的长度为 5,并且数组 \( a \) 的值为 [3, 1, 2, 1, 3]。我们将逐步追踪代码如何操作这个输入并生成输出的两个排列 \( p \) 和 \( q \)。
### 输入过程
- **输入 n = 5**。
- **输入 a = [3, 1, 2, 1, 3]**。
### 初始化排列 \( p \) 和 \( q \)
首先,代码将遍历数组 \( a \),尝试将每个元素尽可能地放入排列 \( p \) 和 \( q \) 中。
- **i = 1**: \( a[1] = 3 \)。因为 \( t1[3] \) 是0,所以 \( p[1] = 3 \),并将 \( t1[3] \) 设为 1。
- **i = 2**: \( a[2] = 1 \)。因为 \( t1[1] \) 是0,所以 \( p[2] = 1 \),并将 \( t1[1] \) 设为 1。
- **i = 3**: \( a[3] = 2 \)。因为 \( t1[2] \) 是0,所以 \( p[3] = 2 \),并将 \( t1[2] \) 设为 1。
- **i = 4**: \( a[4] = 1 \)。因为 \( t1[1] \) 已经是1(\( p[2] = 1 \)),所以 \( q[4] = 1 \),并将 \( t2[1] \) 设为 1。
- **i = 5**: \( a[5] = 3 \)。因为 \( t1[3] \) 已经是1(\( p[1] = 3 \)),所以 \( q[5] = 3 \),并将 \( t2[3] \) 设为 1。
此时,数组 \( p \) 和 \( q \) 的状态为:
- **\( p = [3, 1, 2, 0, 0] \)**
- **\( q = [0, 0, 0, 1, 3] \)**
### 填充未分配的位置
- **i = 1**: \( p[1] \) 和 \( q[1] \) 已分配,跳过。
- **i = 2**: \( p[2] \) 和 \( q[2] \) 已分配,跳过。
- **i = 3**: \( p[3] \) 和 \( q[3] \) 已分配,跳过。
- **i = 4**: \( p[4] \) 未分配:
- 找到 \( j = 4 \) 未被使用,所以 \( p[4] = 4 \),并将 \( t1[4] \) 设为 1。
- \( q[4] \) 已分配,跳过。
- **i = 5**: \( p[5] \) 未分配:
- 找到 \( j = 5 \) 未被使用,所以 \( p[5] = 5 \),并将 \( t1[5] \) 设为 1。
- \( q[5] \) 已分配,跳过。
- 对于 \( q \) 的空位:
- \( q[1] \),找到 \( j2 = 2 \) 未被使用,所以 \( q[1] = 2 \),并将 \( t2[2] \) 设为 1。
- \( q[2] \),找到 \( j2 = 4 \) 未被使用,所以 \( q[2] = 4 \),并将 \( t2[4] \) 设为 1。
- \( q[3] \),找到 \( j2 = 5 \) 未被使用,所以 \( q[3] = 5 \),并将 \( t2[5] \) 设为 1。
### 输出结果
最终排列:
- **\( p = [3, 1, 2, 4, 5] \)**
- **\( q = [2, 4, 5, 1, 3] \)**
代码成功生成了两个有效的排列,每个数字在两个排列中各出现一次。
D.小红升装备
思路:多重背包dp。
#include<bits/stdc++.h>
using namespace std;
long long dp[303][303];
int main(){
int n,i,j,x,k;
cin>>n>>x;
memset(dp,-0x3f,sizeof dp);
dp[0][0] = 0;
long long res = 0;
for(i=1;i<=n;i++){
long long a,b,c,d,e;
cin>>a>>b>>c>>d>>e;
for(j=0;j<=x;j++) dp[i][j] = dp[i-1][j];
for(k=0;k<=x;k++){
for(j=0;j<=e;j++){
if(b+c*j>k){
break;
}
dp[i][k] = max(dp[i][k],dp[i-1][k-(b+c*j)]+a+j*d);
res = max(res,dp[i][k]);
}
}
}
cout<<res<<endl;
return 0;
}
这段代码是用于解决上述问题的动态规划解决方案。这里的目标是最大化小红通过购买和升级装备获得的战力,同时不超过她拥有的金币数。以下是解题思路和代码解释:
动态规划定义
dp[i][j]
表示考虑前i
件装备,使用不超过j
个金币时能获得的最大战力。- 初始条件为
dp[0][0] = 0
,意味着没有装备和没有使用金币时战力为 0。 - 初始化其它值为一个很小的数(这里用
-0x3f3f3f3f
),代表非法状态。
状态转移
对于每件装备,遍历所有可能的金币使用量 k
(0 到 x
),并考虑将该装备升级 j
级(0 到最大等级 e
)。状态转移遵循以下逻辑:
- 若购买该装备并升级
j
级所需的总金币数超过k
,则不可能实现这种情况,结束当前循环。 - 更新
dp[i][k]
为max(dp[i][k], dp[i-1][k-(b+c*j)] + a + j*d)
。这意味着,如果决定购买并升级这个装备j
级,将会消耗b+c*j
金币,且增加的战力为初始战力a
加上j*d
(每级升级的战力)。 - 更新最大战力
res
为遍历过程中所有dp[i][k]
的最大值。
循环结构
- 外层循环遍历装备
i
从 1 到n
。 - 第二层循环遍历金币数
k
从 0 到x
,表示不同的预算情况。 - 内层循环尝试对当前装备进行从 0 到
e
级的升级,并检查是否可能在当前金币预算下完成购买和升级。
输出结果
最终,输出 res
,它表示在给定预算下,通过购买和升级装备可以达到的最大战力。
通过这种方式,代码能够在多重限制下(金币数和装备升级限制)找到最优解。这种问题常见于资源优化和游戏策略开发中,动态规划提供了一种有效的解决方案。
E.小红的矩阵划分
思路:一道思维题,考虑三种情况,一种是全填L,一种是全填2*2,一种是去掉一个L填2*2。
#include<bits/stdc++.h>
using namespace std;
int main(){
long long n,x,y;
cin>>n>>x>>y;
if(n%3==0){
cout<<max(n*n/3*x,n*n/4*y);
}else{
cout<<max({n*n/3*x,n*n/3*x-x+y,n*n/4*y});
}
return 0;
}
算法思路
- 计算
n*n/3
和n*n/4
,这代表如果整个矩阵被 'L' 型或 2*2 连通块完全覆盖,各自能够划分出的最大连通块数。 - 对于每一种情况,计算对应的总分,即
n*n/3*x
或n*n/4*y
。 - 如果
n
不能被 3 整除,则额外计算一个 'L' 型和一个 22 连通块混合的情况,即n*n/3*x-x+y
,这种情况下会牺牲一个 'L' 型连通块和一个格子来放置一个 22 连通块。 - 在所有这些情况中取最大值作为最终得分。
F.小红拿宝箱
太难了,看不懂,跳了。