一维前缀和+二维前缀和

一维前缀和

好资源

Max Subarray Sum

算法思路:对于固定的右边界 j j j,最大子数组和为: p [ j ] − min ⁡ i < j p [ i ] p[j]-\min_{i<j} p[i] p[j]mini<jp[i],可以在遍历右边界的过程中去维护 min ⁡ i ≤ j p [ i ] \min _{i \leq j} p[i] minijp[i],这样可以 O ( 1 ) O(1) O(1) 地求出固定右边界 j j j 的最大子数组和。
模板代码:

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

#define int long long
const int N=1e4+4;
int n,pfx[N],t;

signed main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>t;
		pfx[i]=pfx[i-1]+t;
	}
	int max_subarray_sum=pfx[1],min_prefix_sum=pfx[0];
	for(int i=1;i<=n;++i){
		max_subarray_sum=max(max_subarray_sum,pfx[i]-min_prefix_sum);
		min_prefix_sum=min(min_prefix_sum,pfx[i]);
	} 
	cout<<max_subarray_sum<<'\n';
}

练习题:
Max Subarray Sum
题意:给定一个长为 n n n 的数列,求出最大的子数列和。要求输出 最大子数组和、左边界、有边界。(如果有多个子数组的和最大,输出字典序最小的左边界和有边界)
参考代码:

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

#define int long long
int n,pfx[10004],t,T;
int left_id,right_id,max_subarray_sum,min_prefix_sum;

signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--){
		cin>>n;
		for(int i=1;i<=n;++i){
			cin>>t;
			pfx[i]=pfx[i-1]+t;
		}
		left_id=1,right_id=1;
		int tmp=1;
		max_subarray_sum=pfx[1];
		min_prefix_sum=pfx[0];
		for(int i=1;i<=n;++i){
			if(max_subarray_sum<pfx[i]-min_prefix_sum){
				max_subarray_sum=pfx[i]-min_prefix_sum;
				left_id=tmp;
				right_id=i;
			}
			if(min_prefix_sum>pfx[i]){ //改变左边界 
				min_prefix_sum=pfx[i];
				tmp=i+1;
			}
		}
		cout<<max_subarray_sum<<' '<<left_id-1<<' '<<right_id-1<<'\n'; //数组的下标从0开始
	}
}

二维前缀和

定义:sum[i][j]:表示 ( 1 , 1 , i , j ) (1,1,i,j) (1,1,i,j)所围成的子矩形的前缀和。
预处理:

for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)
		sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];

查询子矩阵 ( x 1 , y 1 , x 2 , y 2 ) (x_1,y_1,x_2,y_2) (x1,y1,x2,y2)的元素和:

int ask(int x1,int y1,int x2,int y2)
{
	return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}

练习题:
Codeforces Round #817 (Div. 4) E. Counting Rectangles
题意:给定 n n n个矩阵,长宽分别为 h , w , h,w, h,w,。有 q q q次询问,每次询问给出 h 1 , w 1 , h 2 , w 2 h_1,w_1,h_2,w_2 h1,w1,h2,w2,问 n n n个给定的矩阵中有多少个矩阵满足 h s < h i < h b  and  w s < w i < w b h_{s}<h_{i}<h_{b} \text { and } w_{s}<w_{i}<w_{b} hs<hi<hb and ws<wi<wb
数据范围: ( 1 ≤ h i , w i ≤ 1000 ) \left(1 \leq h_{i}, w_{i} \leq 1000\right) (1hi,wi1000) ( 1 ≤ n ≤ 1 0 5 ; 1 ≤ q ≤ 1 0 5 ) \left(1 \leq n \leq 10^{5} ; 1 \leq q \leq 10^{5}\right) (1n105;1q105)
解题思路:2D前缀和
参考代码:

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

#define int long long
int T,n,q,a[1003][1003],sum[1003][1003],x,y,h1,w1,h2,w2;

int ask(int x1,int y1,int x2,int y2)
{
	return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}

signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>T;
	while(T--){
		memset(sum,0,sizeof sum);
		memset(a,0,sizeof a);
		cin>>n>>q;
		for(int i=1;i<=n;++i){
			cin>>x>>y;
			a[x][y]+=x*y;
		}	
		for(int i=1;i<=1000;++i)
			for(int j=1;j<=1000;++j)
				sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
		while(q--){
			cin>>h1>>w1>>h2>>w2;
			cout<<ask(h1+1,w1+1,h2-1,w2-1)<<'\n';
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值