题目不赘述了!直接讲讲思路!确实是比较简单的第四题,但本菜狗还是修修改改了多次才拿到100分,来梳理一下解题思路。
思路
每次操作一个格子,将这个格子的水珠+1,如果 5,则将该格子变0,左右两边有水珠的格子中水珠+1,然后从左至右再处理水珠 5的格子,直到所有格子都 5,再进行下一步操作。
1. 看到这个首先想到的是BFS广度优先搜索,将需要进行操作(也就是+1)的格子放入一个队列queue中,每一次从queue中取出队首,判断它是否 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;
}
菜鸟一枚!有问题欢迎讨论指出!