Link
Solve
这道题的题面描述可能有点问题,这道题题面上说是子序列,实际上选的是一个连续的子序列。
由于每次只能选连续的一段,我们就求一个前缀和(S[i]= sum_{j=1}^ia[i])
题目问的是连续一段的总代价在([L,R]),所以
(L≤ sum_{k=i}^{j} a[i]≤R) (Rightarrow L≤S[i]-S[j-1]≤R)
(Rightarrow S[i]-R≤S[j-1]≤S[i]-L,(j≤i))
题目就转化成,枚举到一个(S[i])求之前的,在([S[i]-R,S[i]-L])上(S[j])的个数
用树状数组或者线段树就可以处理了
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=100005;
const LL maxR=1e10;
int N,tot,root;
LL L,R,S[maxn],ans;
struct node{
int lson,rson,sum;
}Tree[13600005];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
inline void push_up(int x){
Tree[x].sum=Tree[Tree[x].lson].sum+Tree[Tree[x].rson].sum;
return ;
}
inline int build(){
++tot;Tree[tot].lson=Tree[tot].rson=Tree[tot].sum=0;
return tot;
}
int update(int x,LL l,LL r,LL pos,int val){
if(!x)x=build();
if(l==r){Tree[x].sum+=val;return x;}
LL mid=r+l>>1;
if(pos<=mid)Tree[x].lson=update(Tree[x].lson,l,mid,pos,val);
else Tree[x].rson=update(Tree[x].rson,mid+1,r,pos,val);
push_up(x);
return x;
}
int query(int x,LL l,LL r,LL ql,LL qr){
if(!x)x=build();
if(ql<=l&&r<=qr)return Tree[x].sum;
LL ret=0,mid=l+r>>1;
if(ql<=mid) ret+=query(Tree[x].lson,l,mid,ql,qr);
if(qr> mid)ret+=query(Tree[x].rson,mid+1,r,ql,qr);
return ret;
}
int main(){
freopen("P5459.in","r",stdin);
freopen("P5459.out","w",stdout);
N=read();L=read();R=read();
for(int i=1;i<=N;i++)S[i]=S[i-1]+read();
root=update(root,-maxR,maxR,S[0],1);
for(int i=1;i<=N;i++){
ans+=query(root,-maxR,maxR,S[i]-R,S[i]-L);
update(root,-maxR,maxR,S[i],1);
}
printf("%lld
",ans);
return 0;
}