问题描述(又是图片QAQ)
问题分析:
先来看差分-前缀和(真的是必看内容,不看不会,一看就会啊):
前缀和与差分 图文并茂 超详细整理(全网最通俗易懂)_林小鹿@的博客-CSDN博客_前缀和与差分
正常情况下是:站在人的角度:当前的qi 推断出地点进入的满足区间,然后遍历地点,这样做两层循环(外层是遍历qi,内层遍历所有地点)
现在反过来思考: 对于一个地方进入的时间ti 可以求出满足进入条件的 核酸检测时间边界为: 、
如此:位于这个区间内的 每个数 都是 符合要求的,我们都给他 +1记一次有效次数,这样 累计了所有场景的有效次数后(每个场景都有不同的区间,叠加起来这些区间),那么当这个人在取某个数qi(也就是进入地方的时间为qi时),有几个叠加的区间,就代表能去的地方有几个。有点像这种:
如此,对于某个区间所有数+1的操作采用 差分-前缀和思想,就能得出下面的代码
解决方案:(差分-前缀和)
这里需要额外注意的两点是:
1.边界必须比0大吧 (就是tl tr那里)(不然整个负的算怎么回事?)
2.另外一点是 构建前缀和数组的时候 没有新开一个数组
(如果开的话 是: a[i]=a[i-1]+v[i],在这里a[i]表示前缀和数组,v[i]还是差分数组!!!!!!)
这样递推的算过来 v[i]=v[i-1] +v[i],这里的v[i]就表示前缀和数组了!!!!! ,说白了就是在原空间上直接算了!
#include<iostream> #include<vector> using namespace std; int main() { int n, m, k; cin >> n >> m >> k; int l, r; vector<int> v(200010); for (int i = 0; i < n; i++) { cin >> l >> r; int tl = max(0, l - r - k + 1);//注意维持边界条件 int tr = max(0, l - k); v[tl]++; //精髓所在 v[tr + 1]--; //精髓所在 } for (int i = 1; i < 200010; i++) { v[i] += v[i - 1]; //没开一个新的 前缀和数组,是因为没必要浪费新的空间 直接在 差分 数组上做计算就行 } //以下是为了满足输出格式 vector<int> a; for (int i = 0; i < m; i++) { cin >> l; a.push_back(v[l]) ; } for(auto i :a) cout<<i<<endl; return 0; }
(以上内容都是个人的理解,第一次写如有不妥的地方,希望指出,可能有些csdn大大的地址也忘了给出了.....)