ProblemA:Serval vs Monster
题目传送门:https://atcoder.jp/contests/abc153/tasks/abc153_a
解题思路:
问你需要多少次技能才能消灭怪兽。
输出 即可,可以转化为
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int h, a;
cin >> h >> a;
cout << ceil(h * 1.0 / a) << endl;
return 0;
}
ProblemB:Common Raccoon vs Monster
题目传送门:https://atcoder.jp/contests/abc153/tasks/abc153_b
解题思路:
给你 和 , 个数组成的技能数组 ,每个技能只能使用过一遍,问你能不能把怪兽的 减到0以下。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, t, a;
cin >> n >> a;
int tot = 0;
for(int i = 0; i < a; ++i) {
cin >> t;
tot += t;
}
if(tot >= n) puts("Yes");
else puts("No");
return 0;
}
Problem C:Fennec vs Monster
题目传送门:https://atcoder.jp/contests/abc153/tasks/abc153_c
解题思路:
题目给出 个技能,可以把怪物血量直接变成0,那么我们对怪物数组从小到大排序,然后输出前 个的和(因为剩下的怪物只能平A了)。
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k, t;
vector<int> health;
cin >> n >> k;
for(int i = 0; i < n; ++i) {
cin >> t;
health.push_back(t);
}
sort(begin(health), end(health));
if(k > n) k = n;
long long tot = accumulate(begin(health), begin(health) + n - k, (long long)0);
cout << tot <<endl;
return 0;
}
Problem D:Caracal vs Monster
题目传送门:https://atcoder.jp/contests/abc153/tasks/abc153_d
解题思路:
我们可以将场上所有的怪兽攻击一次计算为一次攻击,推导可得:
为了体力战胜1只H怪兽所需的攻击次数为
:
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
ll n;
ll now = 1;
ll tot = 0;
cin >> n;
while(n >= 1) {
tot += now;
now <<= 1;
n /= 2;
}
cout << tot << endl;
return 0;
}
Problem E:Crested Ibis vs Monster
题目传送门:https://atcoder.jp/contests/abc153/tasks/abc153_e
解题思路:
这道题是典型的背包dp模板题,就是完全背包条件下,找大于等于最大容量的最小价值。
定义 为前 个咒语造成了 点伤害最少使用的 量,那么状态转移方程为:
时间复杂度:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
const int M = 2e4 + 5;
int a[N], b[N];
int dp[N][M];
int main()
{
int h, n;
cin >> h >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i] >> b[i];
memset(dp, 0x3f, sizeof dp);
dp[0][0] = 0;
for(int i = 1; i <= n; ++i) {
for(int j = 0; j <= h; ++j) {
dp[i][j] = min(dp[i - 1][j], dp[i][max(0, j - a[i])] + b[i]);
}
}
cout << dp[n][h] << endl;
return 0;
}
我们发现,第一维的空间完全可以省略,所以可以简化成如下代码:
即选择下一个技能的话就要加上下一个技能的b[ i ],不选择的话就不加。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
const int M = 2e4 + 5;
int a[N], b[N];
int dp[N];
int main()
{
int h, n;
cin >> h >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i] >> b[i];
memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
for(int i = 1; i <= n; ++i) {
for(int j = 0; j <= h; ++j) {
dp[j] = min(dp[j], dp[max(0, j - a[i])] + b[i]);
}
}
cout << dp[h] << endl;
return 0;
}
Problem F:Silver Fox vs Monster
题目传送门:https://atcoder.jp/contests/abc153/tasks/abc153_f
解题思路:
有 个怪物,每个怪物的坐标为 ,血量为 ,在 处施展一次攻击会对 到 区间内的所有怪物造成 点伤害,怪物的血量小于等于0则死亡,问至少攻击多少次能消灭全部怪物。
我们首先对怪物按坐标进行排序。首先,攻击顺序肯定是不重要的,而且最左边的点如果要被消灭的话一定会被攻击 次,把攻击的血量累计到总伤害,然后后面 的距离都会受到影响,我们需要知道最近不受伤害的点,这个可以使用双指针算法,也可以使用二分,然后运用差分的思想,构建一个差分数组,把这个坐标的值加扣的血量,每次到一个点我们的总伤害先减去这个差分数组,这样就能维护当前被影响的血量。
这里还可以使用线段树或者树状数组来修改区间,可以当做练手来试试。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 50; // 蜜汁RE,不知道为什么,2e5+10就RE
ll c[N];
struct Node {
int x, h;
inline bool operator < (const Node& t) const {
return x < t.x;
}
} p[N];
int main()
{
int n, a, d;
cin >> n >> d >> a;
for(int i = 1; i <= n; ++i)
cin >> p[i].x >> p[i].h;
sort(p + 1, p + n + 1);
ll ans = 0;
// 双指针
for(int i = 1, j = 1; i <= n; ++i) {
while(j <= n && p[j].x <= p[i].x + 2 * d) ++j;
ll need = max((p[i].h - c[i] * a + a - 1) / a, 0ll);
ans += need;
// 构造差分序列
c[i] += need;
c[j] -= need;
c[i + 1] += c[i];
}
cout << ans << endl;
return 0;
}