【CSP考题扩展】前缀和/差分练习

【深进1.例1 求区间和】

题目描述

给定 nnn 个正整数组成的数列 a1,a2,⋯ ,ana_1, a_2, \cdots, a_na1,a2,,anmmm 个区间 [li,ri][l_i,r_i][li,ri],分别求这 mmm 个区间的区间和。

对于所有测试数据,n,m≤105,ai≤104n,m\le10^5,a_i\le 10^4n,m105,ai104

输入格式

第一行,为一个正整数 nnn

第二行,为 nnn 个正整数 a1,a2,⋯ ,ana_1,a_2, \cdots ,a_na1,a2,,an

第三行,为一个正整数 mmm

接下来 mmm 行,每行为两个正整数 li,ril_i,r_ili,ri ,满足1≤li≤ri≤n1\le l_i\le r_i\le n1lirin

输出格式

mmm 行。

iii 行为第 iii 组答案的询问。

1≤n,m≤1051\le n, m\le 10^51n,m1051≤ai≤1041 \le a_i\le 10^41ai104

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;

long long n, m, t, a, b;

int main() {
	cin >> n;
	vector<int>perfix(n + 1, 0), arr(n);

	for (size_t i = 0; i < n; i++)
	{
		cin >> arr[i];
	}
	for (size_t i = 0; i < n; i++)
	{
		perfix[i + 1] = perfix[i] + arr[i];
	}

	cin >> m;
	for (size_t i = 0; i < m; i++)
	{
		cin >> a >> b;
		cout << perfix[b] - perfix[a - 1] << endl;
	}
	return 0;
}

【最大加权矩形】

题目描述

为了更好的备战 NOIP2013,电脑组的几个女孩子 LYQ,ZSC,ZHQ 认为,我们不光需要机房,我们还需要运动,于是就决定找校长申请一块电脑组的课余运动场地,听说她们都是电脑组的高手,校长没有马上答应他们,而是先给她们出了一道数学题,并且告诉她们:你们能获得的运动场地的面积就是你们能找到的这个最大的数字。

校长先给他们一个 n×nn\times nn×n 矩阵。要求矩阵中最大加权矩形,即矩阵的每一个元素都有一权值,权值定义在整数集上。从中找一矩形,矩形大小无限制,是其中包含的所有元素的和最大 。矩阵的每个元素属于 [−127,127][-127,127][127,127] ,例如

 0 –2 –7  0 
 9  2 –6  2
-4  1 –4  1 
-1  8  0 –2

在左下角:

9  2
-4  1
-1  8

和为 151515

几个女孩子有点犯难了,于是就找到了电脑组精打细算的 HZH,TZY 小朋友帮忙计算,但是遗憾的是他们的答案都不一样,涉及土地的事情我们可不能含糊,你能帮忙计算出校长所给的矩形中加权和最大的矩形吗?

输入格式

第一行:nnn,接下来是 nnnnnn 列的矩阵。

输出格式

最大矩形(子矩阵)的和。

#include <iostream>
#include <vector>
#include <climits> // For INT_MIN
#include <algorithm>
using namespace std;

int n, maxSum = INT_MIN;

int main() {
    cin >> n;
    vector<vector<int>> matrix(n, vector<int>(n));
    vector<vector<int>> prefixMatrix(n + 1, vector<int>(n + 1, 0));
    for (auto& it : matrix) {
        for (auto& jt : it) {
            cin >> jt;
        }
    }
    for (size_t i = 1; i < n + 1; i++) {
        for (size_t j = 1; j < n + 1; j++) {
            prefixMatrix[i][j] = prefixMatrix[i][j - 1] + prefixMatrix[i - 1][j] - prefixMatrix[i - 1][j - 1] + matrix[i - 1][j - 1];
        }
    }

    // 遍历所有可能的左上角位置
    for (size_t i = 1; i <= n; i++) {
        for (size_t j = 1; j <= n; j++) {
            // 遍历所有可能的右下角位置
            for (size_t k = i; k <= n; k++) {
                for (size_t p = j; p <= n; p++) {
                    // 使用前缀和矩阵计算当前矩形的和
                    // sum 表示从 (i, j) 到 (k, p) 形成的矩形的加权和
                    int sum = prefixMatrix[k][p] - prefixMatrix[i - 1][p] - prefixMatrix[k][j - 1] + prefixMatrix[i - 1][j - 1];
                    // 更新最大加权和
                    maxSum = max(maxSum, sum);
                }
            }
        }
    }

    cout << maxSum;
    return 0;
}

【语文成绩】

题目背景

语文考试结束了,成绩还是一如既往地有问题。

题目描述

语文老师总是写错成绩,所以当她修改成绩的时候,总是累得不行。她总是要一遍遍地给某些同学增加分数,又要注意最低分是多少。你能帮帮她吗?

输入格式

第一行有两个整数 nnnppp,代表学生数与增加分数的次数。

第二行有 nnn 个数,a1∼ana_1 \sim a_na1an,代表各个学生的初始成绩。

接下来 ppp 行,每行有三个数,xxxyyyzzz,代表给第 xxx 个到第 yyy 个学生每人增加 zzz 分。

输出格式

输出仅一行,代表更改分数后,全班的最低分。

#include <iostream>
#include <vector>
#include <climits> // For INT_MIN
#include <algorithm>
using namespace std;

long long n, p, x, y, z, minGrade = INT_MAX;

int main() {
    cin >> n >> p;
	vector<long long>grade(n);
	vector<long long>diffGrade(n);
	vector<long long>finalGrade(n);
	for (size_t i = 0; i < n; i++)
	{
		cin >> grade[i];
	}

	// 构建差分数组
	diffGrade[0] = grade[0];
	for (size_t i = 1; i < n; i++)
	{
		diffGrade[i] = grade[i] - grade[i - 1];
	}

	// 批量增减
	for (size_t i = 0; i < p; i++)
	{
		cin >> x >> y >> z;
		diffGrade[x - 1] += z;
		if (y < n) diffGrade[y] -= z;
	}

	// 恢复原数组
	finalGrade[0] = diffGrade[0];
	for (size_t i = 1; i < n; i++)
	{
		finalGrade[i] = finalGrade[i - 1] + diffGrade[i];
	}
	for (size_t i = 0; i < n; i++)
	{
		minGrade = min(minGrade, finalGrade[i]);
	}
	cout << minGrade;
    return 0;
}

【地毯】

题目描述

n×nn\times nn×n 的格子上有 mmm 个地毯。

给出这些地毯的信息,问每个点被多少个地毯覆盖。

输入格式

第一行,两个正整数 n,mn,mn,m。意义如题所述。

接下来 mmm 行,每行两个坐标 (x1,y1)(x_1,y_1)(x1,y1)(x2,y2)(x_2,y_2)(x2,y2),代表一块地毯,左上角是 (x1,y1)(x_1,y_1)(x1,y1),右下角是 (x2,y2)(x_2,y_2)(x2,y2)

输出格式

输出 nnn 行,每行 nnn 个正整数。

iii 行第 jjj 列的正整数表示 (i,j)(i,j)(i,j) 这个格子被多少个地毯覆盖。

#include <iostream>
#include <vector>
using namespace std;

int n, m, xx1, xx2, yy1, yy2;

int main() {
    cin >> n >> m;
    vector<vector<int>>diffArea(n, vector<int>(n, 0));
    vector<vector<int>>resultArea(n, vector<int>(n, 0));

    for (size_t i = 0; i < m; i++)
    {
        cin >> xx1 >> yy1 >> xx2 >> yy2;
        for (size_t i1 = xx1 - 1; i1 < xx2; i1++) // 将二维差分数组视为n个大小为n的一维差分数组
        {
            diffArea[i1][yy1 - 1] += 1;
            if (yy2 < n) diffArea[i1][yy2] -= 1;
        }
    }

    for (size_t i = 0; i < n; i++)
    {
        resultArea[i][0] = diffArea[i][0];
        for (size_t j = 1; j < n; j++)
        {
            resultArea[i][j] = resultArea[i][j - 1] + diffArea[i][j];
        }
    }

    for (auto& it : resultArea) {
        for (auto& jt : it) {
            cout << jt << " ";
        }
        cout << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值