安吉D6-T3
- 1安吉D19 T1
- 2安吉D19 T3
- 3安吉D20 模考12总结
- 4安吉D17 T3
- 5安吉D17 T4
- 6安吉D19 模考11总结
- 7安吉D15 A
- 8安吉D16 T4
- 9安吉D17 T1
- 10安吉D17 模考10总结
- 11安吉D16 T3
- 12安吉D16 模考9总结
- 13安吉D13 模考8总结
- 14安吉D13-T2
- 15安吉D13-T3
- 16安吉D12-T3
- 17安吉D11-B
- 18安吉D11-C
- 19安吉D11-D
- 20安吉D12 模考7总结
- 21安吉D12-T2
- 22安吉D11-A
- 23安吉D10 模考6总结
- 24安吉D10-T3
- 25安吉D10-T4
- 26安吉D8-E
- 27安吉D9-T4
- 28安吉D8-A
- 29安吉D8-B
- 30安吉D8-C
- 31安吉D8-D
- 32安吉D9 模考5总结
- 33安吉D9-T2
- 34安吉D9-T3
- 35安吉D6-T4
- 36安吉D4-G
- 37安吉D5-T2
- 38安吉D6 模考4总结
- 39安吉D6-T1
- 40安吉D6-T3本文
- 41安吉-开营测试 T4
- 42安吉D5 模考3总结
- 43安吉D5-T3
- 44安吉D4-A
- 45安吉D4-B
- 46安吉D4-C
- 47安吉D4:容斥原理
- 48安吉Day4-D
- 49安吉D3 模考2总结
- 50安吉D3-T1
- 51安吉D3-T2
- 52安吉D3-T4
- 53安吉D2 模考1总结
- 54安吉D2-T2
- 55安吉D1-G
- 56安吉D1-L
- 57安吉D2-T4
原题呈现
题目描述
小信在玩一款卡牌游戏.对方场上有 张怪物卡,第 张怪物的初始血量为 .
小信有两种攻击方式:
-
群攻:使用一次群攻,会让当前所有存活怪物的血量都减少 . 如果这次减少后存在至少一只怪物血量变为 或更小,这些怪物会立刻死亡,并且群攻效果会立刻再次触发一次(再次让所有仍存活怪物血量减少 ,并且这次额外效果不会消耗群攻次数). 如此反复,只要某一次群攻触发后有怪物死亡,就会继续自动触发下一次群攻;当某一次触发后没有任何怪物死亡时,这张群攻卡牌的效果结束.
-
普攻:一次普攻可以选择任意一只存活怪物,使其血量减少 .
现在有 次询问.每次询问只给出一个整数 ,表示本次询问中小信可以使用 次群攻,普攻的使用次数无限制.小信可以以任意顺序穿插使用群攻与普攻,目标是消灭全部怪物,并使总攻击次数最少.
请你对每次询问输出最少需要多少次攻击.
输入格式
第一行输入一个整数 ,表示怪物数量.
第二行输入 个整数 ,表示各怪物初始血量.
第三行输入一个整数 ,表示询问次数.
接下来 行,每行输入一个整数 ,表示每次询问中小信的群攻次数限制.
输出格式
输出 行.每行输出一次询问的答案:在最优策略下最少需要的总攻击次数.
样例
样例 1
输入:
101 3 2 2 6 7 2 1 2 109123456789输出:
975555555样例 2
输入:
31 1 33321输出:
222数据范围
本题采用捆绑评测,对于一个子任务,你必须通过其中的所有数据才能得到相应分数.
| 子任务编号 | 分数 | 特殊性质 | |
|---|---|---|---|
| 1 | 20 | 无 | |
| 2 | 10 | ||
| 3 | 20 | 无 | |
| 4 | 10 | ||
| 5 | 10 | ||
| 6 | 15 | 无 | |
| 7 | 15 | 无 |
对于所有数据:,.
结论题,结论为:由于值域很小,我们可以将所有数字按值放在一个桶中,桶中所有为 0 的且后面存在非 0 位置的位置视为一个空格.每一次群攻可以消灭一个空格,当场上没有剩余空格时,再进行一次群攻即可消灭全部敌人.
由于群攻总是比普攻不劣,我们先考虑群攻次数足够的情况,此时只需要施展场上空格次数 +1 次群攻即可.
群攻次数不足时呢?我们考虑使用普攻填空格.从后面往前进行遍历,每当遇到一个空格 :
- 若该格右边存在:同种血量的怪物存在多种,则选择血量最接近的一种,该种怪物中的一个通过普攻降到血量 ,来填补这个空格的同时,又不会拆东墙补西墙.
- 否则,选择当前血量最大的怪兽,通过普攻将其血量变为 ,用来填补这个空格.
例如:现在存在 ,将其整理成桶的形式:,所有不存在(即为空格)的数值为 .
从右边开始:
- 对于 ,让 通过一次普攻变成 .此时:.代价为 1.
- 对于 ,让 通过一次普攻变成 .此时:.代价为 1.
- 对于 ,让 通过四次普攻变成 .此时:.代价为 4.
- 对于 ,让 通过六次普攻变成 .此时:.代价为 6.
显然,由于存在群攻,这四次填空格的方式并不需要全部操作.只需要贪心的选择其中的部分空格填上,即选择代价最少的几种.因此:将 4 次操作按照代价从小到大排序,在其中选择 项(其中 是允许群攻的次数),所需代价就是普攻的次数,再加上 次群攻即可.
标程
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N = 1e6 + 100;int n, h[N], q, a[N];ll sum[N];
signed main() {#ifdef ONLINE_JUDGE freopen("profane.in", "r", stdin); freopen("profane.out", "w", stdout);#endif ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n; for (int i = 1; i <= n; i++) { cin >> h[i]; } sort(h + 1, h + n + 1); stack<int> stk; vector<int> vec; int maxh = -1; for (int i = 1; i <= n; i++) { a[h[i]]++; maxh = max(maxh, h[i]); } for (int i = maxh; i >= 1; i--) { if (a[i] > 1) { for (int j = 2; j <= a[i]; j++) stk.push(i); } else if (a[i] == 0) { int cost = 0; if (!stk.empty()) { int tp = stk.top(); stk.pop(); cost = tp - i; } else { cost = maxh - i; maxh--; } vec.push_back(cost); } } sort(vec.begin(), vec.end()); for (int i = 0; i < vec.size(); i++) { sum[i + 1] = sum[i] + vec[i]; } cin >> q; while (q--) { int k; cin >> k; if (k > vec.size()) { cout << vec.size() + 1 << endl; } else { int need = vec.size() - k + 1; cout << sum[need] + k << endl; } } return 0;}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!


