初看这道题,以为又是什么数据结构数数题,没啥思路,结果推式子时搞出了一个类似可以卷积的玩意儿,所以果断 \(FFT\) 解决。
那我们来分析问题:
-
这道题里,值域没用,每一个数只要管它与 \(x\) 的相对大小关系即可。如果它小于 \(x\) 那么有贡献,赋值为一,否则为零。然后,可以求前缀和,区间部分和问题往往可以用前缀和配对端点解决。
-
令 \(f_i\) 表示前缀和为 \(i\) 的前缀端点数量,\(m\) 为总共比 \(x\) 小的数的个数。显然的,对于恰好有大于一个数比 \(x\) 小的情况中,答案 \(g_k = \sum\limits_{i=0}^{m-k} f_i \times f_{i+k}\)。 这个式子意思就是取两个端点使区间值符合条件,然后用加乘原理统计一下。
-
考虑常用技巧,变换顺序,令 \(h_i = f_{m-i}\) ,所以 \(f_{i+k} = h_{m-i-k}\) ,这样的话,\(g\) 就可以写成两者加法卷积了。大功告成。
-
不要忘了特殊处理 \(g_0\) ,经过推导可知 \(g_0 = \sum\limits_{i=0}^m \frac{f_i\times{(f_i + 1)}}{2}\) ,暴力算就好。
struct Vector {
double x, y;
Vector(double _x = 0, double _y = 0) : x(_x), y(_y) {}
inline Vector Vary(void) { return Vector(x, -y); }
inline bool operator < (const Vector&rhs)
const { return x == rhs.x ? y < rhs.y : x < rhs.x; }
inline Vector operator - (const Vector&rhs)
const { return Vector(x - rhs.x, y - rhs.y); }
inline Vector operator + (const Vector&rhs)
const { return Vector(x + rhs.x, y + rhs.y); }
inline Vector operator * (const double&rhs)
const { return Vector(x * rhs, y * rhs); }
inline Vector operator / (const double&rhs)
const { return Vector(x / rhs, y / rhs); }
inline Vector operator * (const Vector&rhs)
const { return Vector(x * rhs.x - y * rhs.y, x * rhs.y + y * rhs.x); }
}; typedef Vector Complex;
const double PI = std :: acos(-1.0);
const int Maxn = 6e5 + 5;
int lim = 1, rev[Maxn];
inline void FFT(int limit, Complex *arr, int type) {
for (int i = 0; i < limit; i++)
if (i < rev[i]) swap(arr[i], arr[rev[i]]);
for (int mid = 1; mid < limit; mid <<= 1) {
Complex w0(cos(PI / mid), type * sin(PI / mid));
for (int i = 0; i < limit; i += mid << 1) { Complex w(1, 0);
for (int j = 0; j < mid; j++, w = w * w0) {
Complex x = arr[i + j], y = w * arr[i + j + mid];
arr[i + j] = x + y, arr[i + j + mid] = x - y;
}
}
} if (type == -1) for (int i = 0; i < limit; i++) arr[i] = arr[i] / limit;
}
int n, m, x; Complex f[Maxn];
signed main(void) {
read(n), read(x);
for (int i = 1, v; i <= n; i++) {
read(v); m += v < x ? 1 : 0; f[m].x++;
}
f[0].x++;
while (lim <= m << 1) lim <<= 1;
for (int i = 0; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (lim >> 1) : 0);
ll ret = 0;
for (int i = 0; i <= m; i++) f[m - i].y = f[i].x, ret += (ll) f[i].x * (f[i].x - 1) / 2;
FFT(lim, f, 1);
for (int i = 0; i < lim; i++) f[i] = f[i] * f[i];
FFT(lim, f, -1);
writeln(ret, ' ');
for (int i = 1; i <= m; i++) writeln((ll) (f[m - i].y / 2.0 + 0.5), ' ');
for (int i = m + 1; i <= n; i++) writeln(0, " \n"[i == n]);
// fwrite(pf, 1, o1 - pf, stdout);
return 0;
}
标签:Statistics,const,int,题解,rhs,Nikita,return,Vector,inline
From: https://www.cnblogs.com/EternalEpic/p/18416766