MAX Average Problem
给你一个数列,求大于给定长度的区间的最大平均值
可以过的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int lis[maxn], head, tail;
char IO_BUF[maxn * 250];
char *buf = IO_BUF;
double dp[maxn];
ll sum[maxn], n, k;
inline void read(ll &a) {
for (a = 0; *buf < 48; buf++);
while (*buf > 47)
a = a * 10 + *buf++ - 48;
}
ll getSum(int i, int j) {
return sum[j] - sum[i];
}
ll getX(int i, int j) {
return j - i;
}
void getY(int i, int j) {
dp[j] = max(dp[j - 1], (sum[j] - sum[i]) * 1.0 / (j - i));
}
int main() {
int tol = fread(IO_BUF, 1, maxn * 250, stdin);
while (buf - IO_BUF + 1 < tol) {
read(n);
read(k);
for (int i = 1; i <= n; i++) {
read(sum[i]);
sum[i] += sum[i - 1];
}
memset(dp, 0, sizeof(dp));
head = tail = 0;
for (int i = k; i <= n; i++) {
while (head + 1 < tail && getSum(lis[tail - 1], i - k) * getX(lis[tail - 2], lis[tail - 1]) <=
getX(lis[tail - 1], i - k) * getSum(lis[tail - 2], lis[tail - 1])) {
--tail;
}
lis[tail++] = i - k;
while (head + 1 < tail && getSum(lis[head], i) * getX(lis[head + 1], i) <=
getX(lis[head], i) * getSum(lis[head + 1], i)) {
++head;
}
getY(lis[head], i);
}
printf("%.2f\n", dp[n]);
}
return 0;
}
直接套模板会超时
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1e5 + 100;
int n, k, head, tail;
double sum[maxn], dp[maxn];
int q[maxn], a[maxn];
//输入加速
int input() {
char ch = ' ';
int num = 0;
while (ch < '0' || ch > '9') {
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
num = num * 10 + ch - '0';
ch = getchar();
}
return num;
}
int gety(int y1, int y2) {
return sum[y2] - sum[y1];
}
int getx(int x1, int x2) {
return x2 - x1;
}
double solve() {
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + a[i] * 1.0;
}
head = 0, tail = 1;
q[head = 0];
double ans = 0;
for (int i = k; i <= n; i++) {
int j = i - k;
while (head + 1 < tail && gety(q[tail - 1], j) * getx(q[tail - 2], q[tail - 1]) <=
gety(q[tail - 2], q[tail - 1]) * getx(q[tail - 1], j)) {
tail--;
}
q[tail++] = j;
while (head + 1 < tail && gety(q[head], i) * getx(q[head + 1], i) <= gety(q[head + 1], i) * getx(q[head], i)) {
head++;
}
dp[i] = (sum[i] - sum[q[head]]) / (i - q[head]);
ans = max(ans, dp[i]);
}
return ans;
}
int main() {
while (scanf("%d%d", &n, &k) != EOF) {
for (int i = 1; i <= n; i++) {
a[i] = input();
}
printf("%0.2lf\n", solve());
}
return 0;
}
需要二分查找
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define ll long long
const int maxn = 1e5 + 100;
int n, k, head, tail;
double sum[maxn], dp[maxn];
int q[maxn], a[maxn];
//输入加速
int input() {
char ch = ' ';
int num = 0;
while (ch < '0' || ch > '9') {
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
num = num * 10 + ch - '0';
ch = getchar();
}
return num;
}
int gety(int y1, int y2) {
return sum[y2] - sum[y1];
}
int getx(int x1, int x2) {
return x2 - x1;
}
ll check(int mid, int i) {
return gety(q[mid + 1], i) * getx(q[mid], q[mid + 1]) - gety(q[mid], q[mid + 1]) * getx(q[mid + 1], i);
}
int search(int l, int r, int i) {
//由于斜率单调递增
/*int top=r;
while(l<=r){//根据i与mid的斜率 和 i与mid+1的斜率之差求切点
if(l == r && l == top)return q[l];//这里一定要注意如果切点是最后一个点需要另判,因为mid+1不存在会出错
int mid=(l+r)>>1;
if(check(mid,i)<0)r=mid-1;
else l=mid+1;
}*/
while (l < r) {//根据i与mid的斜率 和 i与mid+1的斜率之差求切点
int mid = (l + r) >> 1;
if (check(mid, i) < 0)r = mid;
else l = mid + 1;
}
return q[l];
}
double solve() {
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + a[i] * 1.0;
}
int p;//q[head]
head = 0, tail = 1;
q[head = 0];
double ans = 0;
for (int i = k; i <= n; i++) {
int j = i - k;
while (head + 1 < tail && gety(q[tail - 1], j) * getx(q[tail - 2], q[tail - 1]) <=
gety(q[tail - 2], q[tail - 1]) * getx(q[tail - 1], j)) {
tail--;
}
q[tail++] = j;
p = search(head, tail - 1, i);
dp[i] = (sum[i] - sum[p]) / (i - p);
if (dp[i] > ans)ans = dp[i];
}
return ans;
}
int main() {
while (scanf("%d%d", &n, &k) != EOF) {
for (int i = 1; i <= n; i++) {
a[i] = input();
}
printf("%0.2lf\n", solve());
}
return 0;
}