题解:
1.IST20013的帮助
2.编程反思:1.能少开数组就少开数组2.没有精度要求统一用long long 3.学会去优化
3.题目思路:
1.平均值一定在-1e6和1e6之间因此直接用二分去逼近
2.让每个区间的元素都减去这个平均值,其中用到前缀和,然后最后求出区间和,若大于0则mid满足,继续寻找更大的数
3.优化代码:
for(int i=1;i<=n;i++)
{
sum[i]=sun[i-1]+(a[i]-mid);//预处理
}
for(int i=m;i<=n;i++)
{
for(int j=i-m;j>=0;j--)//保证长度至少为m 但是发现这段是在求最小值
{
if(sum[i]-sum[i-m]>=0){return true;}
}
}
这个时间复杂度较高,因此采用以下优化
for (int i = 1; i <= n; i++)
{
sum[i] = sum[i - 1] + (a[i] - mid);//区间每个元素都减去平均数
if (i >= len)
{
minn = min(minn, sum[i - len]);
if (sum[i] >= minn)
//减去一个最小和仍大于0 即证明该平均数是可以的 学会去优化 减少循环次数
{
flag = 1;
break;
}
}
}
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include<iostream>
#include<limits.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 1;
ll minn;
ll a[N],sum[N];//原序列,减去mid后的序列,前缀和序列
int main()
{
int T;
cin >> T;
while (T--)
{
memset(a, 0, sizeof(a));
memset(sum, 0, sizeof(sum));
int n, len;
scanf("%d%d", &n, &len);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);//统一用long long
}
ll l = -1e6, r = 1e6;
ll mid=(l + r + 1) / 2;
while (l<r)
{
bool flag = 0;
minn = INT_MAX;
mid = (l + r+1) / 2;
for (int i = 1; i <= n; i++)
{
sum[i] = sum[i - 1] + (a[i] - mid);//区间每个元素都减去平均数
if (i >= len)
{
minn = min(minn, sum[i - len]);
if (sum[i] >= minn)//减去一个最小和仍大于0 即证明该平均数是可以的 学会去优化 减少循环次数
{
flag = 1;
break;
}
}
}
/*
for(int i=1;i<=n;i++)
{
sum[i]=sun[i-1]+(a[i]-mid);//预处理
}
for(int i=m;i<=n;i++)//时间复杂度(n-m)*(i-m)
{
for(int j=i-m;j>=0;j--)//保证长度至少为m 但是发现这段是在求最小值
{
if(sum[i]-sum[i-m]>=0){return true;}
}
}
*/
if (0 != flag)
{
l = mid;
}
else
{
r = mid - 1;
}
}
printf("%d\n", int(r));
}
return 0;
}