第33次CCF/CSP-十滴水-题解

题目不赘述了!直接讲讲思路!确实是比较简单的第四题,但本菜狗还是修修改改了多次才拿到100分,来梳理一下解题思路。

思路

每次操作一个格子,将这个格子的水珠+1,如果 \geq 5,则将该格子变0,左右两边有水珠的格子中水珠+1,然后从左至右再处理水珠 \geq 5的格子,直到所有格子都 < 5,再进行下一步操作。

1. 看到这个首先想到的是BFS广度优先搜索,将需要进行操作(也就是+1)的格子放入一个队列queue中,每一次从queue中取出队首,判断它是否 \geq 5 ,是的话就要将它所在的格子水滴数置0,并且去找它左右两边最近的、都有水珠的格子,将找到的格子进行+1操作,并且放入queue中;否的话就直接不用管它。队列也要使用优先队列,这样每次取出来的都是最左边的格子,符合题目要求。

2.这道题的时间复杂度就出现在如何寻找到 爆开水珠格子的左右两边最近的、有水珠的格子。一开始用的是两个while循环往前找、往后找,但这样会超时。于是想到用set来存储当前有水珠的格子的下标,set正好不允许重复且排序的,假如我们想要找下标为3的格子的前后有水珠的格子,只需要用迭代器 iterator 指向 s.find(3),然后进行 ++ i 和 -- i即可,当然还需要特判边界情况!最终我们只需要返回s.size()就可以得到答案了。

(set中的find是用红黑树实现的,其时间复杂度为O(logn))

3.其实可以发现,我们完全没有用到没有水滴的格子。一开始我是用一个int数组来存放水滴数,因为报runtime error错,感觉是数据范围问题。于是改成了用map存储所有有水珠的格子,就ac了。

代码

#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;

typedef long long int ll;
ll c,m,n;
unordered_map<int,int> h;
priority_queue< ll,vector<ll>,greater<ll> > q;
set<ll> s; 

void bfs()
{
	while(!q.empty())
	{
		ll t = q.top();
		q.pop();
		if(h[t] >= 5)
		{
			h[t] = 0;
			set<ll>::iterator i;
			i = s.find(t);
			if(i != s.begin())
			{
				i -- ;
				h[*i] += 1;
				q.push(*i); 
			}
			i = s.find(t);
			if(++i != s.end())
			{
				h[*i] += 1;
				q.push(*i);
			}
			s.erase(t);
		}
	}
	
}


int main(int argc, char** argv) {
	
	cin >> c >> m >> n;
	while(m--)
	{
		ll pos,nums;
		cin >> pos >> nums;
		h[pos] = nums;
		s.insert(pos);
	}

	while(n--)
	{
		int op;
		cin >> op;
		h[op] += 1;
		q.push(op);
		bfs();
		cout << s.size() << endl;
	}
	return 0;
}

菜鸟一枚!有问题欢迎讨论指出!

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值