初看这道题,以为又是什么数据结构数数题,没啥思路,结果推式子时搞出了一个类似可以卷积的玩意儿,所以果断 \(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;
}