Educational Codeforces Round 122 (Rated for Div. 2)

文章讨论了在EducationalCodeforcesRound122中的两道编程竞赛题目。C题涉及利用有限的操作机会优化角色的攻击力和血量,以确保能击败怪物。关键在于枚举增加攻击力的次数,并计算角色和怪物的生存轮数。D题则是一个关于预处理和01背包的问题,需要找到将1变成给定数字所需最小步骤,并应用到01背包的动态规划解决方案上。
摘要由CSDN通过智能技术生成

Educational Codeforces Round 122 (Rated for Div. 2)

C题

因为你有 k k k次操作机会,而又因为题目中告诉我们 ∑ k ≤ 2 × 1 0 5 \sum k\le 2\times10^5 k2×105,所以可以枚举哪几次增加攻击力,剩下的增加血量。

假设当前枚举到 i i i,那么当前的攻击力就是 d c + i × w dc+i\times w dc+i×w,血量就是 h c + ( k − i ) × a hc+(k-i)\times a hc+(ki)×a

然后分别计算怪物打死角色需要多少轮,角色打死怪物需要多少轮。

需要注意的几点

  • long long!
  • 一开始我先算角色打死怪物需要多少轮,然后看角色是否被打死,但判断角色是否被打死的时候会爆unsigned long long,所以还是要把他们分别算出来。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int T;
ull hC, hM, dC, dM, k, w, a;
int main() {
    scanf("%d", &T);
    while (T--) {
        cin >> hC >> dC >> hM >> dM >> k >> w >> a;
        bool ok = false;
        for (int i = 0; i <= k; ++i) {
            ull d = dC + i * w;
            ull h = hC + (k - i) * a;
            ull t = (hM + (d - 1)) / d;
            ull p = (h + (dM - 1)) / dM;
            // cout << d << ' ' << h << ' ' << t << ' ' << (t - 1) * dM << endl;
            if (p < t) continue;
            puts("YES");
            ok = true;
            break;
        }
        if (!ok) puts("NO");
    }
    return 0;
}

D题

因为 a i a_i ai初始都是 1 1 1,所以我们想到预处理出来 f 1 i f1_i f1i表示 1 1 1变成 i i i所需的最小步数。那么 f 1 i + i j = min { f 1 i + 1 } f1_i+\frac ij=\text{min}\{f1_{i}+1\} f1i+ji=min{f1i+1}

那么对于每组数据, f 1 b i f1_{b_i} f1bi实际就相当于体积, c i c_i ci就是价值,然后就是01背包了。

#include<bits/stdc++.h>
using namespace std;
const int N = 1010, M = 100010;
int T;
int n, k;
int b[N], c[N];
int f1[N], f[M];
void init() {
    memset(f1, 0x3f, sizeof(f1));
	f1[1] = 0;
	for (int i = 1; i <= 1000; ++i) {
		for (int j = 1; j <= 1000; ++j) {
			int u = i * 1.0 / j;
			if (u + i <= 1000) f1[u + i] = min(f1[u + i], f1[i] + 1);
		}
	}
}
int main(){
	init();
	scanf("%d", &T);
	while(T--) {
		scanf("%d%d", &n, &k);
		k = min(k, 12 * n);
        memset(f, 0, sizeof(f));
		for (int i = 1; i <= n; ++i) {
            scanf("%d", &b[i]);
            b[i] = f1[b[i]];
        }
		for (int i = 1; i <= n; ++i) scanf("%d", &c[i]);
		for (int i = 1; i <= n; ++i)
			for (int j = k; j >= b[i]; --j)
                f[j] = max(f[j], f[j - b[i]] + c[i]);
		printf("%d\n", f[k]);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值