本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前置知识
前缀和
一维前缀和: 一维前缀和:
初始化:
for(int i=1;i<=n;i++)
s[i] = s[i-1] + a[i];
二维前缀和:
: 第i行第j列左上部分所有元素的和
以为左上角,为右下角的子矩阵的和为:
矩阵长宽都为1
矩阵长宽都为k
差分
差分数组b[i]代表a[i]-a[i-1]两个元素之间的差
给区间中的每个数加上c:
两者结合
差分数组b[i]=a[i]-a[i-1]
差分前缀和数组s[i]=s[i-1]+b[i]
做区间修改时一直进行差分数组的操作,最后统计时利用差分数组计算差分前缀和。
注意是差分前缀和,是最后一个值与前面初始值之间(初始值如果用的是0,则表示当前值)的差距,而不是真正的前缀和。
为区间修改之后的a[i]
题目
蓝彗星
链接:
ac.nowcoder.com/acm/contest…
s1[i]:代表B的差分
s2[i]:代表R的差分
对差分求前缀和得到的是当前值,如果当前值为正说明存在,为0说明不存在
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int main()
{
vector<int>s1(N,0),s2(N,0);
int n,t;
cin>>n>>t;
string s;
cin>>s;
for(int i=1;i<=n;i++)
{
int x;cin>>x;
if(s[i-1]=='B') s1[x]++, s1[x+t]--;
else s2[x]++, s2[x+t]--;
}
int res = 0;
for(int i=1;i<=2e5;i++)
{
s1[i] += s1[i-1];
s2[i] += s2[i-1];
res += (s1[i] && !s2[i]);
}
cout<<res<<endl;
return 0;
}
把它当成思维题来写:
bl,br为B的左右区间
R只负责对B的区间进行切割
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const int N = 1e5+5;
pair<int,char>p[N];
int main()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>p[i].se;
for(int i=1;i<=n;i++) cin>>p[i].fi;
sort(p+1,p+1+n);
ll res = 0;
int bl = 0,br = 0;
int rl=0,rr=0;
for(int i=1;i<=n;i++)
{
if(p[i].se == 'B') //yanxu jisuan
{
if(p[i].fi>br)
{
res += max(br-bl,0);
bl = max(rr,p[i].fi);
br = p[i].fi + k;
}
else br = max(p[i].fi + k,br);
}
if(p[i].se == 'R')//qiege
{
br = min(p[i].fi,br);
rr = max(rr,p[i].fi + k);
}
// cout<<bl<<"--"<<br<<endl;
}
if(bl and br) res += max(br-bl,0);
cout<<res<<endl;
return 0;
}