2024年蓝桥杯第三场小白赛 召唤神坤 知识点:预处理

101 阅读1分钟

1.召唤神坤【算法赛】 - 蓝桥云课 (lanqiao.cn)

暴力

枚举j,然后枚举j左边的i,j右边的k。然后三层循环,j最多枚举n,i和k最多各自枚举一半,合起来就是n,一共复杂度就是O(n^2),n的最大范围是1e5,双层循环1e10,会超时:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int w[N];
int ans;

int main() {
	int n;
	cin >> n;


	for (int i = 0; i < n; i++)
		cin >> w[i];

	//枚举j
	for (int j = 1; j < n - 1; j++) {
		for (int i = 0; i < j; i++) {
			for (int k = j + 1; k < n; k++) {
				ans = max(ans, (w[i] + w[k]) / w[j]);
			}
		}
	}

	cout << ans << endl;
	return 0;
}

只过了9%: image.png

暴力方法就是三层循环枚举w[i],w[j],w[k],n最大1e5,三层循环肯定超时

优化做法

只枚举j,i和k我们通过计算的方式去求,这样j最多O(n),i,j只需要O(1),最多就只要O(n)的复杂度。

我们这里把a,c数组预处理出来,保证a数组是前缀最大数组,c数组是后缀最大数组。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],b[N],c[N];
int main()
{
	int n;cin>>n;
	for(int i=1;i<=n;i++)cin>>b[i];
	
	//求一下前缀最大
	for(int i=1;i<=n;i++) a[i]=max(a[i-1],b[i]);
	
	//求一下后缀最大
	for(int i=n;i>=1;i--) c[i]=max(c[i+1],b[i]);
	
	int res=0;
       //枚举每个w[j],找值最大的
	for(int i=2;i<=n;i++)res=max(res,(a[i-1]+c[i+1])/b[i]);
	cout<<res;
	return 0;
}

image.png

过程模拟:

image.png

image.png