感谢大佬给的思路,这里修改了一部分大佬的代码,这个代码应该更好的可以理解,并且强调了一些容易错的地方。计算方差的公式有很多,大佬使用的公式和我使用的公式本质上都是一样的,选取自己喜欢的即可
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 100010;
ll n, k, t;
ll a[N], b[N];
ll mid;
bool check(ll n) {
if (k <= 0) return false; // 确保 k 合法,避免除零错误
for (ll i = 1; i <= n; i++) b[i] = a[i];
sort(b + 1, b + 1 + n);
ll sum_num = 0, sum_num2 = 0;
// 初始窗口的平方和与和
for (ll i = 1; i <= k; i++) {
sum_num2 += b[i] * b[i];
sum_num += b[i];
}
// 检查初始窗口的方差
ll variance = sum_num2 * k - sum_num * sum_num;
if (variance <= t * k * k) return true; // 使用整除以避免浮点异常
// 滑动窗口
for (ll i = k + 1; i <= n; i++) {
// 移除窗口左端的元素
sum_num2 -= b[i - k] * b[i - k];
sum_num -= b[i - k];
// 添加窗口右端的元素
sum_num2 += b[i] * b[i];
sum_num += b[i];
// 计算方差
variance = sum_num2 * k - sum_num * sum_num;
//这个地方采用的公式是概率论中的经典:D[X]=E[x^2]-(E[X])^2,但是注意调整k的位置防止精度损失
//避免写成variance = sum_num2 / k - sum_num /k * sum_num/k<t;
if (variance < t * k * k) return true; // 使用整数运算避免浮点异常
}
return false;
}
int main() {
cin >> n >> k >> t;
for (int i = 1; i <= n; i++) cin >> a[i];
if (!check(n)) { // 特判一下边界
cout << -1;
return 0;
}
ll l = k, r = n;
while (l < r) { // 二分答案
mid = (l + r) >> 1;
if (check(mid))
r = mid;
else
l = mid + 1;
}
cout << l;
return 0;
}