题解:P10450 [USACO03MAR] Best Cow Fences G

题目链接

博客食用体验更佳

$ O(n^3) $ 做法

  1. 第一层循环先跑一遍长度(题目有限制长度不小于 $ L $)。

  2. 第二层循环跑一遍起点,千万要注意不要越界 QwQ。

  3. 最后再遍历这个区间求最大值。

附上我丑陋的代码和提交记录,这个代码可以得 42 分。

#include <bits/stdc++.h>
using namespace std;

const int NR = 1e5 + 5;
long long n, l, a[NR], sum, ave;

int main() {
	cin >> n >> l;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = l; i <= n; i++) //先枚举长度
		for (int j = 1; j <= n - i + 1; j++) { //枚举起点
			sum = 0;
			for (int k = j; k <= j + i - 1; k++)//遍历,求和
				sum += a[k];
			ave = max(ave, sum * 1000 / i);
		}
	cout << ave;
	return 0;
}

$ O(n^2) $ 做法

根据上面,我们可以发现求和的那段过程可以用前缀和优化,我们可以先 $ O(n) $ 预处理前缀和,再枚举。

如何预处理前缀和

我们用 \(s_i\) 表示前缀和。

\[s_i = \sum_{j = 1}^i a_j \]

\(s\) 数组的递推方式如下。

\[s_i = s_{i - 1} + a_i \]

不懂的可以看前缀和代码,大家也可以拿这道题练练手。

下面是我丑陋的代码和提交记录,我们已经可以拿到 70 分了。

#include <bits/stdc++.h>
using namespace std;

const int NR = 1e5 + 5;
long long n, l, a[NR], s[NR], sum, ave;

int main() {
	cin >> n >> l;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i];//前缀和预处理 
	for (int i = l; i <= n; i++) //同上,先枚举长度
		for (int j = 1; j <= n - i + 1; j++) { //枚举起点
			sum = s[j + i - 1] - s[j - 1];//求区间和
			ave = max(ave, sum / i * 1000);
		}
	cout << ave;
	return 0;
}

$ O(n \log W) $ 做法

我们发现这道题平均数越小越容易达到,符合二分的特点。我们可以找一个数值,再判断是否符合要求。

check 函数该怎么写

这次前缀和与上面有点不同。

  1. 前缀和:这次前缀和表示前缀和与理想的总和的差。
  2. 为什么要累求最小值:因为想让平均数越大减的就需要越小。
  3. 平均数若大于理想的平均数,就返回真,否则返回假。
  4. 不知道说啥了,送大家一个我用的二分板子

哦对了,我把 \(s\) 数组的递推式写上

\[s_i = s_{i - 1} + a_i - mid \]

历尽千辛万苦,我们 AC 了这道题,最后贴上我丑陋的代码和提交记录

#include <bits/stdc++.h>
using namespace std;

const int NR = 1e5 + 5;
long long n, L;
double l = 0, r = 2e3, s[NR], a[NR];//s[i]表示前缀和与理想的总和的差

bool check(double mid) {
	for (int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i] - mid; 
	double minn = 0;
	for (int i = L; i <= n; i++) {//枚举起点
		minn = min(minn, s[i - L]);//累求最小值 
		if(s[i] - minn >= 0)
			return 1; 
	}
	return 0;
}

int main() {
	cin >> n >> L;
	for (int i = 1; i <= n; i++) cin >> a[i];
	while (r - l > 1e-5) {
		double mid = (l + r) / 2;
		if(check(mid)) l = mid;
		else r = mid;
	}
	cout << int(r * 1000);
	return 0;
}

题解结束了,有问题欢迎大家私信我。

posted @ 2024-07-24 15:18  0x3f3f3f3f3f3f  阅读(26)  评论(0编辑  收藏  举报