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 成文


posted @ 2022-01-18 14:40  hh2048  阅读(57)  评论(0编辑  收藏  举报