| 时间限制 | 内存限制 | 
|---|---|
1000 ms | 
65536 KB | 
# 题目描述
「暮念」正在教「瑄瑄」玩一款风靡全国的名为《农》的 MOBA 类游戏,现在进行新手教程,系统为「瑄瑄」安排了一名由她操控的英雄「妲己」和 个敌方小兵。游戏规则如下:
- 
「妲己」每秒可以对一个小兵造成固定 点伤害;第 个小兵的生命值为 ,如果第 个小兵存活(即 ),每秒钟会对「妲己」造成 点伤害。
 - 
每一秒中,在小兵对「妲己」造成伤害之后,「瑄瑄」可以操控「妲己」对一个存活的小兵 进行攻击,使 减少 ,当 时,该小兵阵亡。击杀所有小兵即可通过新手教程。
 
由于是新手教程,「妲己」无论受到多少伤害都不会死亡,但是「暮念」要求使「妲己」尽可能少地受到伤害,否则就要狠狠地惩罚「瑄瑄」。
请你计算出「妲己」受到的最少伤害,帮助「瑄瑄」通过新手教程而不被惩罚。
# 输入格式
第一行输入 个整数 和 个整数 ,,。
第二行输入 个整数 ,。
第三行输入 个整数 ,。
# 输出格式
输出  个整数,表示「妲己」受到的最少伤害。数据保证这个数一定在  long long  范围内。
# 输入样例 1
4 4  | |
1 2 3 4  | |
4 5 6 8  | 
# 输出样例 1
39  | 
# 输入样例 2
1 4  | |
1 1 1 1  | |
1 2 3 4  | 
# 输出样例 2
20  | 
# 输入样例 3
8 1  | |
40  | |
59  | 
# 输出样例 3
320  | 
# 题解:贪心 + 排序
首先考虑是逐个击破好还是雨露均沾好。对于两个敌人,不论是逐个击破还是雨露均沾,第二个敌人阵亡的时间都是不变的,对玩家的伤害也是固定的,而雨露均沾会拉长对第一个敌人的战线,使其对玩家造成更高的伤害。由此可见,逐个击破才是最佳策略。
接下来我们要考虑按照什么顺序逐个击破。考虑到敌人的伤害同时受到血量和伤害的影响,我们考虑将它们按照一定指标排序,这就要用到贪心里的邻项交换法了。考虑 两个敌人,假设先打 受到的伤害比先打 受到的伤害小,则我们可以列出如下不等式:
因此我们将 个敌人按照 从小到大排序,逐个击破,受到的伤害最小。
注意到数据范围有 ,浮点数误差不可忽略,所以我们要尽可能避免浮点数计算。具体来说:
- 
;
 - 
将分式不等式写作交叉相乘的形式。
 
时间复杂度:。
参考代码:
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
#define EPS 1e-6 | |
typedef long long ll;  | |
int A, n, d[100010], h[100010];  | |
ll time, harm;  | |
struct Enemy  | |
{ | |
int d, h;  | |
} enemy[100010];  | |
int Cmp(const void *a, const void *b)  | |
{ | |
struct Enemy x = *(struct Enemy*)a;  | |
struct Enemy y = *(struct Enemy*)b;  | |
if (1ll * ((x.h - 1) / A + 1) * y.d > 1ll * ((y.h - 1) / A + 1) * x.d)  | |
return 1;  | |
    else | |
return -1;  | |
} | |
int main()  | |
{ | |
    // freopen("T.in", "r", stdin); | |
    // freopen("T.out", "w", stdout); | |
scanf("%d%d", &A, &n);  | |
for (int i = 1; i <= n; ++ i)  | |
scanf("%d", &enemy[i].d);  | |
for (int i = 1; i <= n; ++ i)  | |
scanf("%d", &enemy[i].h);  | |
qsort(enemy + 1, n, sizeof(enemy[1]), Cmp);  | |
for (int i = 1; i <= n; ++ i)  | |
    { | |
time += ((enemy[i].h - 1) / A + 1);  | |
harm += time * enemy[i].d;  | |
    } | |
printf("%lld\n", harm);  | |
return 0;  | |
} |