Description:
求每个区间和对应的长度和。
Solution:
考虑
cdq
c
d
q
分治,计算跨过中点的串的答案,那么两次
FFT
F
F
T
即可计算出来。
#include <bits/stdc++.h>
using namespace std;
#define double long double
const int maxn = 4e5 + 5;
const double pi = acos(-1);
int n, N, len, S;
int s[maxn];
long long ans[maxn];
struct data {
double x, y;
data() {}
data(double _x, double _y) : x(_x), y(_y) {}
inline data friend operator - (const data &a, const data &b) {
return data(a.x - b.x, a.y - b.y);
}
inline data friend operator + (const data &a, const data &b) {
return data(a.x + b.x, a.y + b.y);
}
inline data friend operator * (const data &a, const data &b) {
return data(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
}
} a[maxn], b[maxn];
void fft(data *a, int f) {
int n = 1 << len;
for(int i = 0; i < n; ++i) {
int t = 0;
for(int j = 0; j < len; ++j) {
if(i & (1 << j)) {
t |= 1 << (len - j - 1);
}
}
if(i < t) {
swap(a[i], a[t]);
}
}
for(int l = 2; l <= n; l <<= 1) {
int m = l >> 1;
data w = data(cos(pi / m), f * sin(pi / m));
for(int i = 0; i < n; i += l) {
data t = data(1, 0);
for(int k = 0; k < m; ++k, t = t * w) {
data x = a[k + i], y = t * a[i + k + m];
a[k + i] = x + y;
a[i + m + k] = x - y;
}
}
}
if(f == -1) {
for(int i = 0; i < n; ++i) {
a[i].x /= n;
}
}
}
void cdq(int l, int r) {
if(l == r) {
ans[s[l]] += 1.0;
return;
}
int mid = (l + r) >> 1;
cdq(l, mid);
cdq(mid + 1, r);
int sum = 0, tot = 0;
for(int i = l; i <= r; ++i) {
tot += s[i];
}
for(n = 1, len = 0; n <= tot; n <<= 1) {
++len;
}
for(int i = 0; i < n; ++i) {
a[i] = b[i] = data(0, 0);
}
sum = 0;
for(int i = mid; i >= l; --i) {
sum += s[i];
a[sum].x += mid - i + 1;
}
sum = 0;
for(int i = mid + 1; i <= r; ++i) {
sum += s[i];
++b[sum].x;
}
fft(a, 1);
fft(b, 1);
for(int i = 0; i < n; ++i) {
a[i] = a[i] * b[i];
}
fft(a, -1);
for(int i = 0; i <= tot; ++i) {
ans[i] += (long long)(a[i].x + 0.1);
}
for(int i = 0; i < n; ++i) {
a[i] = b[i] = data(0, 0);
}
sum = 0;
for(int i = mid; i >= l; --i) {
sum += s[i];
++a[sum].x;
}
sum = 0;
for(int i = mid + 1; i <= r; ++i) {
sum += s[i];
b[sum].x += i - mid;
}
fft(a, 1);
fft(b, 1);
for(int i = 0; i < n; ++i) {
a[i] = a[i] * b[i];
}
fft(a, -1);
for(int i = 0; i <= tot; ++i) {
ans[i] += (long long)(a[i].x + 0.1);
}
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
memset(ans, 0, sizeof(ans));
scanf("%d", &N);
S = 0;
for(int i = 1; i <= N; ++i) {
scanf("%d", &s[i]);
S += s[i];
}
for(int i = 0; i <= S; ++i) {
ans[i] = 0;
}
cdq(1, N);
for(int i = 0; i <= S; ++i) {
printf("%lld\n", ans[i]);
}
}
return 0;
}