传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4627
首先求一个前缀和,问题转化为计数
Sj−Si∈[L,R](i<j)
变形求对于每个
Sj
,求有多少
Si∈[Sj−R,Sj−L](i<j)
做法很多,我用了值域线段树。
#include<stdio.h>
#define cll const ll &
#define cint const int &
#define M 2333333
#define N 100005
#define inf 10000000005LL
typedef long long ll;
int tot,n,l,r,rt;
ll ans,a,la,L,R;
struct node{int k,l,r;}t[M];
void ins(int &k,cll l,cll r)
{
if (k==0) k=++tot;
t[k].k++;
if (l==r) return;
ll mid=l+r>>1;
if (L<=mid){ins(t[k].l,l,mid);return;}
ins(t[k].r,mid+1,r);
}
void find(cint k,cll l,cll r)
{
if (!k) return;
if (L<=l && r<=R)
{
ans+=t[k].k;
return;
}
ll mid=l+r>>1;
if (L<=mid) find(t[k].l,l,mid);
if (mid<R) find(t[k].r,mid+1,r);
}
int main()
{
scanf("%d%d%d",&n,&l,&r);
ins(rt,-inf,inf);
for (int i=1;i<=n;i++)
{
scanf("%lld",&a),a+=la;
L=a-r,R=a-l;find(1,-inf,inf);
L=a;ins(rt,-inf,inf);
la=a;
}
printf("%lld",ans);
}
补一个CDQ分治
#include<stdio.h>
#include<algorithm>
#define cint const int &
typedef long long ll;
ll a[100050],ans;
int n,L,R;
void solve(cint l,cint r)
{
if (r<=l) return;
int mid=l+r>>1;
solve(l,mid);solve(mid+1,r);
int s=l,e=l-1;
for (int i=mid+1;i<=r;i++)
{
while (s<=mid && a[s]+R<a[i]) s++;
while (e<mid && a[e+1]+L<=a[i]) e++;
ans+=std::max(e-s+1,0);
}
std::sort(a+l,a+r+1);
}
int main()
{
scanf("%d%d%d",&n,&L,&R);
for (int i=1;i<=n;i++) scanf("%lld",a+i),a[i]+=a[i-1];
solve(0,n);
printf("%lld",ans);
}