ACM 前缀和

前缀和是一种重要的预处理,能大大降低查询的时间复杂度。我们可以简单理解为“数列的前 n 项的和”。

下面是两道简单的前缀和题目

一、一维前缀和

题目链接:洛谷 P3406 海底高铁
在这里插入图片描述
就像公路上限速标志一样,只会在一个路段开始和结束两个地点声明限速和解除限速,而不必在全程每一根柱子上都标明限速70。那么这个题使用前缀和后也是一样,不必在每条路上都标记走了多少次,而只需要在开始和结束处做加一和减一标记处理。这样我们就知道接下来经过的这条路是被经过了多少次,而到了减一的城市之后,接下来经过的路段就与之前的路无关了。
代码:

#include <iostream>
#include <string.h>
using namespace std;

#define LL long long
int n, m, x, y;
LL ans = 0;
ll a, b, c, p[100005], val[100005];

LL Min(LL x, LL y) {
    if (x < y)
		return x;
    else
		return y;
}

LL Max(LL x, LL y) {
    if (x > y)
		return x;
    else
		return y;
}

int main() {
	int n, m;
    cin>>n>>m;
    for(int i=1; i<=m; i++)
		cin>>p[i];
    memset(val, 0, sizeof(val));
    for(int i=1; i<m; i++){
        x = Max(p[i], p[i+1]);
        y = Min(p[i], p[i+1]);
        val[y]++;
        val[x]--;
    }
    for(int i=1; i<=n; i++)
		val[i] += val[i-1];
    for(int i=1; i<n; i++) {
        cin>>a>>b>>c;
        ans += Min(a * val[i], b * val[i] + c);
    }
    cout<<ans<<endl;
    
    return 0;
}

二、二维前缀和

题目链接:洛谷 P2004 领地选择

在这里插入图片描述唯一需要注意的就是,设 s [ i ] [ j ] s[i][j] s[i][j]代表从(1, 1)到(i, j)这一子矩阵的元素和。则左上角坐标为 ( x 1 , y 1 ) (x_1, y_1) (x1,y1),右上角坐标为 ( x 2 , y 2 ) (x_2, y_2) (x2,y2)的子矩阵的元素之和为:
s [ i ] [ j − 1 ] + s [ i − 1 ] [ j ] − s [ i − 1 ] [ j − 1 ] + m p [ i ] [ j ] s[i][j-1] + s[i-1][j] - s[i-1][j-1] + mp[i][j] s[i][j1]+s[i1][j]s[i1][j1]+mp[i][j]

代码:

#include <iostream>
#include <string.h>
using namespace std;
#define maxn 1005

int n, m, c, x, y;
int maxx = -0x7fffffff;
int mp[maxn][maxn], s[maxn][maxn];

int main() {
    cin>>n>>m>>c;
    //dp,求左上角坐标为(1,1),右下角坐标为(x,y)的子矩阵的元素和 
    for(int i=1; i<=n; ++i)
    	for(int j=1; j<=m; ++j) {
			cin>>mp[i][j];
			s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + mp[i][j];
		}

    for(int i=c; i<=n; ++i)
		for(int j=c; j<=m; ++j) {
			if(s[i][j] - s[i-c][j] - s[i][j-c] + s[i-c][j-c] > maxx) {
			   maxx = s[i][j] + s[i-c][j-c] - s[i-c][j] - s[i][j-c];
			   x = i - c + 1;
			   y = j - c + 1;
		}
	}
    printf("%d %d", x, y);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值