一维、二维滑动窗口(蓝桥杯真题)

刷题的过程发现蓝桥杯还挺喜欢考滑动窗口的题,所以索性拿两道典型的真题来说一下滑动窗口的问题

1、子串简写(一维滑动窗口)

题目链接:P9244 [蓝桥杯 2023 省 B] 子串简写 - 洛谷

一维、二维滑动窗口(蓝桥杯真题)_第1张图片


题目解析:

        本题要求找到所有长度大于等于k且首为c1尾为c2的字符串个数,常规思路就是暴力打表,但是仔细看一下题上数据就知道这个方法是肯定会超时的,所以要就用滑动窗口优化一下。


解题思路:

        首先将左边界设为1,右边界设为k,这样的话窗口里的元素始终是大于等于k个的。让窗口从左到右进行滑动,如果左边界找到一次c1,就让它的计数器cnt++,同理,如果右边界找到c2的话就让相应的计数器ans+=cnt。因为窗口始终是大于等于k的,前边的所有c1和此时的c2都能组成合法的字符串。这样只将整个序列遍历了一次,只是一个O(n)的复杂度,可以很轻松的通过这道题。


AC Code:

#include 
using namespace std;
int main()
{
	int k;
	string s;
	char c1,c2;
	cin >> k >> s >> c1 >> c2;
	long long ans=0,cnt=0;
	for(int l=0,r=k-1; r

2、统计子矩阵(二维前缀和+二维滑动窗口) 

 题目链接:P8783 [蓝桥杯 2022 省 B] 统计子矩阵 - 洛谷

一维、二维滑动窗口(蓝桥杯真题)_第2张图片


题目解析:

        在这个矩阵中有多少个小矩阵的和大于k,一涉及到和的问题就知道肯定要用二维前缀和来进行优化,但是即使是这样,由于子矩阵实在是太多,如果直接进行遍历,复杂度就是O(n^{4})。即使这个题的数据并不大,但是这样还是会超时。所以就要用到二维滑动窗口。


解题思路:

        首先计算出整个矩阵的前缀和,然后先用两层循环确定上下边界,再用两个指针作为左右边界,形成一个二维的滑动窗口,通过计算区域和与k的值进行比较来计算符合条件的个数。这样的话左右边界只将序列遍历了一次,算上上下边界的循环时间复杂度就是O(n^{3}),本题500的数据量是可以过的。


AC Code:

#include 
using namespace std;
typedef long long ll;
const int N = 550;
ll a[N][N],sum[N][N];
ll GetSum(int u, int d, int l, int r)
{
	//计算区域和 
	return sum[d][r]-sum[u-1][r]-sum[d][l-1]+sum[u-1][l-1];
}
int main()
{
	ll n,m,k,ans=0;
	cin >> n >> m >> k;
	for(int i=1; i<=n; i++)
	{
		for(int j=1; j<=m; j++)//正常计算二维前缀和 
		{
			cin >> a[i][j];
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
		}
	}

	for(int i=1; i<=n; i++)//下边界
		for(int j=1; j<=i; j++)//上边界 
		{
			for(int l=1, r=1; r<=m; r++)
			{
				while(l<=r && GetSum(j,i,l,r)>k) l++;
				if(l<=r) ans += r-l+1;
			}
		}
	cout << ans;
	return 0;
}

你可能感兴趣的:(蓝桥杯,职场和发展,算法)