CF1266E - Spaceship Solitaire(数据结构 + 贪心 + 模拟 / 铜牌级)
1266E - Spaceship Solitaire(源地址自⇔CF1266E)
tag
⇔数据结构、⇔贪心、⇔模拟、⇔铜牌级(*2100)
题意
建造空间站一共要使用到 \(n\) 种资源,每种资源所需的数量在 \(a[1...n]\) 中给出。每一回合你可以任选一种资源进行建造,一回合只能建造一个。额外提供了 \(m\) 项里程碑式的奖励,每个里程碑的格式为 \(s_i,t_i,u_i\) ,表示当建造了 \(t_i\) 个 \(s_i\) 号资源,奖励 \(1\) 个 \(u_i\) 号资源( \(u_i=0\) 代表无奖励)。若后面给出的里程碑需求与前面给出的一致,则直接替换掉前面的里程碑;保证所有的里程碑的需求 \(t_i\) 不会超过对应的 \(a_{s_i}\) 。
现在,请你求出当只有前 \(k\) ( \(k = 1, 2, 3, ..., n\) )个里程碑时完成空间站需要的最少回合数。
思路
有下述几项显然的结论:
- 由于所有里程碑的需求都是可以达到的,所以我们只需要考虑赠送的资源是否是有用的,如果是有用的,那么可以减少一回合的生产。
- 由于存在顶替情况,我们可以使用 \(\tt{map}\) 数组加以记录。如果可以顶替,那么需要先将被顶替的里程碑所赠送的资源收回。
AC代码
点击查看代码
//====================
LL n, ans, num, need[MAX], extra[MAX], m, s, t, u;
bool Ans;
map<pair<LL, LL>, LL> M;
//====================
void Clear() {
ans = 0; Ans = true;
}
void Solve() {
cin >> n;
FOR(i, 1, n) {
cin >> need[i];
ans += need[i];//最大操作数
}
cin >> m;
FOR(i, 1, m) {
cin >> s >> t >> u;
if(M[{s, t}] != 0) {
/*删除此前一个里程碑对答案的影响*/
LL pre = M[{s, t}];
extra[pre] --;//收回赠送的资源
if(extra[pre] < need[pre]) ans ++;
//当额外赠送的资源 <= 需要的资源时,说明奖励是有用的
//可以减少一回合的生产,故直接在答案上操作
}
M[{s, t}] = u;
extra[u] ++;
if(extra[u] <= need[u]) ans --;
cout << ans << endl;
}
}
错误次数
无
文 / WIDA
2022.01.18 成文
首发于WIDA个人博客,仅供学习讨论
更新日记:
2022.01.18 成文