题意:
给你一个长度为n的数组,让你取一段子区间使得这个区间里值得和>=L,<=R
问你有多少个本质不同的区间。
题解:
难点在于本质不同。
我一开始想的是后缀自动机,但是发现忘了怎么做了,而且好像比较难处理。
转换成后缀数组时,发现height数组是知道排名为i和排名为i-1的后缀的最长公共前缀的,那么我们只需要按照sa数组的顺序便利,查询的区间是height[i]+sa[i]到n。
由于我找的后缀数组的板子,计算是从0到n-1的,所以做起来会比较麻烦。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+10;
int wa[N],wb[N],wv[N],we[N],rk[N];
int cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
void build_sa(int *r,int *sa,int n,int m){
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++)we[i]=0;
for(i=0;i<n;i++)we[x[i]=r[i]]++;
for(i=1;i<m;i++)we[i]+=we[i-1];
for(i=n-1;i>=0;i--)sa[--we[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p){
for(p=0,i=n-j;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=0;i<n;i++)wv[i]=x[y[i]];
for(i=0;i<m;i++)we[i]=0;
for(i=0;i<n;i++)we[wv[i]]++;
for(i=1;i<m;i++)we[i]+=we[i-1];
for(i=n-1;i>=0;i--)sa[--we[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
int height[N];
void calheight(int *r,int *sa,int n){
int i,j,k=0;
for(i=1;i<=n;i++)rk[sa[i]]=i;
for(i=0;i<n;height[rk[i++]]=k){
for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
}
}
int ls[N*40],rs[N*40],rt[N*40],tot;
int num[N*40];
int a[N],sa[N];
ll b[N],sum[N];
void update(int l,int r,int root,int last,int pos)
{
ls[root]=ls[last];
rs[root]=rs[last];
num[root]=num[last]+1;
if(l==r)
return ;
int mid=l+r>>1;
if(mid>=pos)
update(l,mid,ls[root]=++tot,ls[last],pos);
else
update(mid+1,r,rs[root]=++tot,rs[last],pos);
}
ll query(int l,int r,int root,int last,int ql,int qr)
{
if(l>=ql&&r<=qr)
return num[root]-num[last];
int mid=l+r>>1;
ll ans=0;
if(mid>=ql)
ans=query(l,mid,ls[root],ls[last],ql,qr);
if(mid<qr)
ans+=query(mid+1,r,rs[root],rs[last],ql,qr);
return ans;
}
int main()
{
int n;
ll L,R;
scanf("%d%lld%lld",&n,&L,&R);
int all=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
sum[i]=(i-1>=0?sum[i-1]:0)+a[i];
b[++all]=sum[i];
b[++all]=a[i];
}
sort(b+1,b+1+all);
all=unique(b+1,b+1+all)-b-1;
for(int i=0;i<n;i++)
a[i]=lower_bound(b+1,b+1+all,(ll)a[i])-b;
build_sa(a,sa,n+1,N-1);
calheight(a,sa,n);
for(int i=1;i<=n;i++){
int x=lower_bound(b+1,b+1+all,sum[i-1])-b;
update(1,all,rt[i]=++tot,rt[i-1],x);
}
ll ans=0;
for(int i=1;i<=n;i++){
int pos=sa[i]+1;
ll s=pos>=2?sum[pos-2]:0;
int l=lower_bound(b+1,b+1+all,s+L)-b;
int r=upper_bound(b+1,b+1+all,s+R)-b-1;
if(l<=r)
ans+=query(1,all,rt[n],rt[pos+height[i]-1],l,r);
}
printf("%lld\n",ans);
return 0;
}
/**/