蓝桥杯-防御力
1.题目描述
小明最近在玩一款游戏。对游戏中的防御力很感兴趣。
我们认为直接影响防御的参数为“防御性能”,记作d,而面板上有两个防御值A和B,与d成对数关系,A=2d,B=3dA=2 注意任何时候上式都成立)。
在游戏过程中,可能有一些道具把防御值A增加一个值,有另一些道具把防御值B增加一个值。现在小明身上有n1个道具增加A的值和n2个道具增加B的值,增加量已知。
现在已知第i次使用的道具是增加A还是增加B的值,但具体使用那个道具是不确定的,请找到一个字典序最小的使用道具的方式,使得最终的防御性能最大。
初始时防御性能为0,即d=0,所以A=B=1。
输入
输入的第一行包含两个数n1,n2,空格分隔。
第二行n1个数,表示增加A值的那些道具的增加量。
第三行n2个数,表示增加B值的那些道具的增加量。
第四行一个长度为n1+n2的字符串,由0和1组成,表示道具的使用顺序。0表示使用增加A值的道具,1表示使用增加B值的道具。输入数据保证恰好有n1个0,n2个1。
输出
对于每组数据,输出n1+n2+1行,前n1+n2行按顺序输出道具的使用情况,若使用增加A值的道具,输出Ax,x为道具在该类道具中的编号(从1开始)。若使用增加B值的道具则输出Bx。最后一行输出一个大写字母E。
样例输入
1 2
4
2 8
101
样例输出
B2
A1
B1
E
2.题解
2.1 贪心算法
思路
这里的贪心证明使用数学证明并不好证,但我们可以先确定可能的贪心策略,并带入具体数据进行测试,选出最优解(做题技巧)
一共有四种贪心策略:
1.A道具效果从小到大使用,B道具效果从小到大使用
2.A道具效果从小到大使用,B道具效果从大到小使用
3.A道具效果从大到小使用,B道具效果从大到小使用
4.A道具效果从大到小使用,B道具效果从小到大使用
检测:
好的,为了证明策略2(即 A 道具效果从小到大使用,B 道具效果从大到小使用)是最优的,让我们选择一个具体的例子,并进行详细计算和比较。
示例
假设输入数据如下:
- ( n1 = 2 ), ( n2 = 2 )
- 增加 ( A ) 值的道具增加量:[4, 6]
- 增加 ( B ) 值的道具增加量:[8, 3]
- 使用顺序:[0, 1, 0, 1]
四种贪心策略:
策略1:A 道具效果从小到大使用,B 道具效果从小到大使用
- A 道具:[4, 6]
- B 道具:[3, 8]
使用顺序:[0, 1, 0, 1]
- 使用 A 道具4:
- ( $A = 1 + 4 = 5 $)
- ( \(d = \log_2(5) \approx 2.322\) )
- ( \(B = 3^{2.322} \approx 10.6\) )
- 使用 B 道具3:
- ( $B = 10.6 + 3 = 13.6 )
- ( $d = \log_3(13.6) \approx 2.311 $)
- ( \(A = 2^{2.311} \approx 4.92\) )
- 使用 A 道具6:
- ( $A = 4.92 + 6 = 10.92 )
- ( \(d = \log_2(10.92) \approx 3.457\) )
- ( \(B = 3^{3.457} \approx 40.95\) )
- 使用 B 道具8:
- ( $B = 40.95 + 8 = 48.95 $)
- ( $d = \log_3(48.95) \approx 3.663 $)
- ( $A = 2^{3.663} \approx 12.9 $)
最终防御性能 ( $d \approx 3.663 $)。
策略2:A 道具效果从小到大使用,B 道具效果从大到小使用
- A 道具:[4, 6]
- B 道具:[8, 3]
使用顺序:[0, 1, 0, 1]
- 使用 A 道具4:
- ( $A = 1 + 4 = 5 $)
- ( \(d = \log_2(5) \approx 2.322\) )
- ( \(B = 3^{2.322} \approx 10.6\) )
- 使用 B 道具8:
- ( \(B = 10.6 + 8 = 18.6\))
- ( \(d = \log_3(18.6) \approx 2.715\) )
- ( \(A = 2^{2.715} \approx 6.55\) )
- 使用 A 道具6:
- ( \(A = 6.55 + 6 = 12.55\) )
- ( \(d = \log_2(12.55) \approx 3.647\) )
- ( \(B = 3^{3.647} \approx 53.1\) )
- 使用 B 道具3:
- ( $B = 53.1 + 3 = 56.1 $)
- ( \(d = \log_3(56.1) \approx 3.828\) )
- ( \(A = 2^{3.828} \approx 14.5\) )
最终防御性能 ( $d \approx 3.828 $)。
策略3:A 道具效果从大到小使用,B 道具效果从大到小使用
- A 道具:[6, 4]
- B 道具:[8, 3]
使用顺序:[0, 1, 0, 1]
- 使用 A 道具6:
- ( \(A = 1 + 6 = 7\) )
- ( \(d = \log_2(7) \approx 2.807\) )
- ( \(B = 3^{2.807} \approx 18.5\) )
- 使用 B 道具8:
- ( \(B = 18.5 + 8 = 26.5\) )
- ( $$d = \log_3(26.5) \approx 3.008$ )
- ( \(A = 2^{3.008} \approx 8.03\) )
- 使用 A 道具4:
- ( \(A = 8.03 + 4 = 12.03\) )
- ( \(d = \log_2(12.03) \approx 3.584\) )
- ( \(B = 3^{3.584} \approx 49.9\) )
- 使用 B 道具3:
- ( \(B = 49.9 + 3 = 52.9\) )
- ( \(d = \log_3(52.9) \approx 3.775\) )
- ( \(A = 2^{3.775} \approx 13.9\) )
最终防御性能 ( \(d \approx 3.775\) )。
策略4:A 道具效果从大到小使用, B 道具效果从小到大使用
- A 道具:[6, 4]
- B 道具:[3, 8]
使用顺序:[0, 1, 0, 1]
- 使用 A 道具6:
- ( $A = 1 + 6 = 7 $)
- ( \(d = \log_2(7) \approx 2.807\) )
- ( \(B = 3^{2.807} \approx 18.5\) )
- 使用 B 道具3:
- ( \(B = 18.5 + 3 = 21.5\) )$
- ( \(d = \log_3(21.5) \approx 2.924\) )
- ( \(A = 2^{2.924} \approx 7.56\) )
- 使用 A 道具4:
- ( \(A = 7.56 + 4 = 11.56\) )
- ( \(d = \log_2(11.56) \approx 3.529\) )
- ( \(B = 3^{3.529} \approx 47.9\) )
- 使用 B 道具8:
- ( \(B = 47.9 + 8 = 55.9\) )
- ( \(d = \log_3(55.9) \approx 3.825\) )
- ( \(A = 2^{3.825} \approx 14.48\) )
最终防御性能 ( d \approx 3.825 )。
结论
通过比较不同策略的最终防御性能 (d):
- 策略1:( \(d \approx 3.663\) )
- 策略2:( $d \approx 3.828 $)
- 策略3:( \(d \approx 3.775\) )
- 策略4:( \(d \approx 3.825\) )
可以看出,策略2(A道具效果从小到大使用,B道具效果从大到小使用)得到了最高的最终防御性能 ( \(d \approx 3.828\) )。
因此,策略2在这个例子中确实是最优的。
然后我们很容易发现使用第2种策略是最优的,大概数学证明如下:
我们可以发现A和B增大同样的大小,\(d=log_2(A), d=log_3(B)\), A对于d的影响更大,提升速度更快,由于增大量x是固定的,但是每次对d的影响实际上取决于 x/A, 我们希望每次增量都使这种提升最大,充分利用每一次增量,就要求每次使用这个x之前,之前积累的和A越小越好,也就是A增量从小到大,但同时B的增大也会通过影响d反过来影响A的增大,我们希望尽量减小A的增大,也就是令x/B越小越好,让B从大到小即可。
代码
#include<bits/stdc++.h>
using namespace std;
bool compare1(pair<int,int> p1, pair<int, int> p2){
if(p1.second != p2.second)
return p1.second < p2.second;
return p1.first <= p2.first;
}
bool compare2(pair<int,int> p1, pair<int, int> p2){
if(p1.second != p2.second)
return p1.second > p2.second;
return p1.first <= p2.first;
}
int main(){
int n1, n2;
cin >> n1 >> n2;
vector<pair<int,int>> items1(n1), items2(n2);
for(int i = 0; i < n1; i++){
items1[i].first = i + 1;
cin >> items1[i].second;
}
for(int i = 0; i < n2; i++){
items2[i].first = i + 1;
cin >> items2[i].second;
}
string op;
cin >> op;
sort(items1.begin(), items1.end(),compare1);
sort(items2.begin(), items2.end(), compare2);
int cnt1 = 0, cnt2 = 0;
for(char ch : op){
if(ch == '0'){
printf("A%d\n",items1[cnt1++].first);
} else{
printf("B%d\n",items2[cnt2++].first);
}
}
printf("E");
return 0;
}