链接
n 个数, 还有 L, R, 问有多少个本质不同的区间和在 L R 之间。
先考虑一个问题 , 长度为 n 的字符串, 求本质不同的子串有多少个。
n * (n + 1 ) / 2
然后在减去 height[i] , 这种是求总的, 然后减去重复的。n - (sa[i] - 1)- height[i]
, 把所有子串的结果加起来就好了。这样加起来就没有重复的了。在回到这个题:
首先, 读入数据, 然后前缀和, 然后 把原有数据和前缀和离散化, 然后把 前缀和用主席树存起来。
然后考虑怎么把所有区间不重复的加起来。
把原始数据用后缀数组处理一下, 得到 sa, height,
对于排名为 i 的串, 起始位置为 sa[i] 和 排名 i - 1 的串重复 height 个,
所以问题转化成, 我以 sa[i] 为 起始点, 枚举 j, j 在 [l, r] 区间里面, 有多少 j 满足sum[j] - sum[sa[i] - 1]
在 L R 之间,
所以转化成了 有多少个 j , 满足 sum[j] 在 sum[sa[i]-1] + L, sum[sa[i] - 1] + R 之间, 用主席树查询。
#include
using namespace std;
const int N = 5e5+100;
typedef long long ll;
ll b[N*2],L,R,sum[N],tim;
int n,a[N];
int rt[N],ls[N*40],rs[N*40],val[N*40],cnt;
void update(int &now, int l, int r, int k){
++cnt; ls[cnt] = ls[now];
rs[cnt] = rs[now];
val[cnt] = val[now] + 1; now = cnt;
if (l + 1 == r) return;
int mid = (l + r) >> 1;
if (k < mid) update(ls[now], l, mid, k);
else update(rs[now], mid, r, k);
}
int ask(int pre, int now, int l, int r, int ll, int rr){
if (ll <= l && rr >= r - 1){
return val[now] - val[pre];
}
int mid = (l + r) >> 1;
if (ll >= mid) return ask(rs[pre], rs[now], mid, r, ll, rr);
else if (rr < mid) return ask(ls[pre], ls[now], l, mid, ll, rr);
else return ask(rs[pre], rs[now], mid, r, ll, rr) + ask(ls[pre], ls[now], l, mid, ll, rr);
}
namespace SA{
int y[N*2], x[N*2], c[N*2], sa[N], rk[N], height[N];
void get_SA(int *s, int m) {
for (int i = 1; i <= n; ++i) ++c[x[i] = s[i]];
for (int i = 2; i <= m; ++i) c[i] += c[i - 1];
for (int i = n; i >= 1; --i) sa[c[x[i]]--] = i;
for (int k = 1; k <= n; k <<= 1) {
int num = 0;
for (int i = n - k + 1; i <= n; ++i) y[++num] = i;
for (int i = 1; i <= n; ++i) if (sa[i] > k) y[++num] = sa[i] - k;
for (int i = 1; i <= m; ++i) c[i] = 0;
for (int i = 1; i <= n; ++i) ++c[x[i]];
for (int i = 2; i <= m; ++i) c[i] += c[i - 1];
for (int i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
swap(x, y);
x[sa[1]] = 1; num = 1;
for (int i = 2; i <= n; ++i)
x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
if (num == n) break;
m = num;
}
}
void get_height(int *s) {
int k = 0;
for (int i = 1; i <= n; ++i) rk[sa[i]] = i;
for (int i = 1; i <= n; ++i) {
if (rk[i] == 1) continue; //第一名height为0
if (k) --k;//h[i]>=h[i-1]+1;
int j = sa[rk[i] - 1];
while (j + k <= n && i + k <= n && s[i + k] == s[j + k]) ++k;
height[rk[i]] = k; //h[i]=height[rk[i]];
}
}
};
int main(){
scanf("%d%lld%lld",&n,&L,&R);
for (int i = 1; i <= n; ++i){
scanf("%d",&a[i]);
sum[i] = sum[i-1] + a[i];
b[++tim] = a[i];
b[++tim] = sum[i];
}
sort(b+1,b+tim+1);
tim = unique(b+1,b+tim+1) - b - 1;
// for (int i = 1; i <= tim; ++i)
// printf("%lld ",b[i]);
// printf("\n");
for (int i = 1; i <= n; ++i){
a[i] = lower_bound(b+1,b+tim+1,a[i]) - b;
int tmp = lower_bound(b+1,b+tim+ 1,sum[i]) - b;
// printf("%lld %d\n",sum[i], tmp);
rt[i] = rt[i-1];
update(rt[i], 1, tim+1, tmp);
}
SA::get_SA(a, tim+1);
SA::get_height(a);
int ans = 0,l,r;
for (int i = 1; i <= n; ++i){
l = lower_bound(b+1, b+tim+1,sum[SA::sa[i] - 1] + L) - b;
r = upper_bound(b+1, b+tim+1,sum[SA::sa[i] - 1] + R) - b - 1;
// printf("%d %d %d %d %d\n",i,l,r,SA::sa[i] - 1 + SA::height[i], n);
if (l <= r)
ans += ask(rt[SA::sa[i] - 1 + SA::height[i]], rt[n], 1, tim + 1, l, r);
}
printf("%d\n",ans);
return 0;
}