题解 CF993E 【Nikita and Order Statistics】

初看这道题,以为又是什么数据结构数数题,没啥思路,结果推式子时搞出了一个类似可以卷积的玩意儿,所以果断 \(FFT\) 解决。

那我们来分析问题:

  1. 这道题里,值域没用,每一个数只要管它与 \(x\) 的相对大小关系即可。如果它小于 \(x\) 那么有贡献,赋值为一,否则为零。然后,可以求前缀和,区间部分和问题往往可以用前缀和配对端点解决。

  2. \(f_i\) 表示前缀和为 \(i\) 的前缀端点数量,\(m\) 为总共比 \(x\) 小的数的个数。显然的,对于恰好有大于一个数比 \(x\) 小的情况中,答案 \(g_k = \sum\limits_{i=0}^{m-k} f_i \times f_{i+k}\)。 这个式子意思就是取两个端点使区间值符合条件,然后用加乘原理统计一下。

  3. 考虑常用技巧,变换顺序,令 \(h_i = f_{m-i}\) ,所以 \(f_{i+k} = h_{m-i-k}\) ,这样的话,\(g\) 就可以写成两者加法卷积了。大功告成。

  4. 不要忘了特殊处理 \(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;
}
posted @ 2024-09-16 23:44  EternalEpic  阅读(38)  评论(0)    收藏  举报