2023河南萌新联赛第(六)场:河南理工大学-L 阴晴不定的大橘学长
https://ac.nowcoder.com/acm/contest/63602/L?&headNav=acm
文章目录
- 2023河南萌新联赛第(六)场:河南理工大学-L 阴晴不定的大橘学长
- 题意
- 解题思路
- 代码
题意
现在给你一个临界值
x
x
x,并给你
n
n
n个时刻,第
i
i
i个时刻的值是
a
i
a_i
ai,对于任意的
[
l
,
r
]
[l,r]
[l,r]时间段内如果
(
∑
i
=
l
r
a
i
)
≥
x
(\sum_{i=l}^ra_i)\ge x
(∑i=lrai)≥x,说明在这个时间段内是合法的。 现在请你来编写程序求解从
1
1
1到
n
n
n时刻内有多少时间段是合法的。
注意:只要时间段
[
l
,
r
]
[l,r]
[l,r]中
l
l
l与
r
r
r有一个不同,便可认定为不同时间段。
解题思路
先对于该序列求一个前缀和 p r e {pre} pre,确定区间 [ l , r ] [l,r] [l,r]合法表现为保证 p r e r − p r e l − 1 ≥ x pre_r-pre_{l-1}\ge x prer−prel−1≥x,变形一下,可以得到 p r e l − 1 ≤ p r e r − x pre_{l-1}\le pre_r-x prel−1≤prer−x,可以对于每个确定的 r r r,查找在它之前的 p r e l − 1 ≤ p r e r − x pre_l-1\le pre_r-x prel−1≤prer−x的 l l l,可以从值域线段树中求。可以先将数值离散化,从左往右扫,每处理完一个就加入值域线段树,注意最开始要加入 0 0 0保证 [ i , i ] ( a i ≥ x ) [i,i](a_i\ge x) [i,i](ai≥x)也被计算。
代码
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
using namespace std;
const int N=2e5+5;
ll ans,p[N];
ll t[N<<3];
ll n,k,a[N],b[N<<1],cnt;
map<ll,int>ma;
void add(int x,int l,int r,int d){
if(l==r){
t[x]++;
return ;
}
int mid=l+r>>1;
if(d<=mid)add(x<<1,l,mid,d);
else add(x<<1|1,mid+1,r,d);
t[x]=t[x<<1]+t[x<<1|1];
}
ll query(int x,int l,int r,int R){
if(r<=R){
return t[x];
}
int mid=l+r>>1;
if(R<=mid)return query(x<<1,l,mid,R);
return query(x<<1,l,mid,R)+query(x<<1|1,mid+1,r,R);
}
int main(){
cin>>n>>k;
b[++cnt]=0;
for(int i=1;i<=n;i++)cin>>a[i],p[i]=p[i-1]+a[i],b[++cnt]=p[i]-k,b[++cnt]=p[i];
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
for(int i=1;i<=cnt;i++){
ma[b[i]]=i;
}
add(1,1,cnt,ma[0]);
for(int j=1;j<=n;j++){
ans+=query(1,1,cnt,ma[p[j]-k]);
add(1,1,cnt,ma[p[j]]);
}
cout<<ans;
}