洛谷-算法2-1-前缀和、差分与离散化1

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

题目描述

给定由 n 个正整数组成的序列 a1​,a2​,⋯,an​ 和 m 个区间 [li​,ri​],分别求这 m 个区间的区间和。

输入格式

第一行包含一个正整数 n,表示序列的长度。

第二行包含 n 个正整数 a1​,a2​,⋯,an​。

第三行包含一个正整数 m,表示区间的数量。

接下来 m 行,每行包含两个正整数 li​,ri​,满足 1≤li​≤ri​≤n。

输出格式

共 m 行,其中第 i 行包含一个正整数,表示第 i 组答案的询问。

输入输出样例

输入 #1复制

复制代码
4
4 3 2 1
2
1 4
2 3

输出 #1复制

复制代码
10
5

说明/提示

样例解释

第 1 到第 4 个数加起来和为 10。第 2 个数到第 3 个数加起来和为 5。

数据范围

对于 50% 的数据:n,m≤1000;

对于 100% 的数据:1≤n,m≤105,1≤ai​≤104。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int a[111100];
int sum[111001];

int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum[i]+=sum[i-1]+a[i];
	}
	int m;
	cin>>m;
	for(int i=1;i<=m;i++){
		int l,r;
		cin>>l>>r;
		cout<<sum[r]-sum[l-1]<<endl;
	}
	return 0;
}

P1719 最大加权矩形

题目描述

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

校长给她们一个大小为 n×n 的矩阵,矩阵中的每一个元素都有一个整数权值,要她们求出该矩阵中的最大加权矩形(即从中找一大小不限的矩形,使其中包含的所有元素的权值和最大)中所有元素的权值和,且矩阵中每个元素的权值均在区间 [−127,127] 内。

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

输入格式

第一行包含一个正整数 n。

接下来 n 行每行包含 n 个整数,表示给定的矩阵。

输出格式

输出一行一个整数,表示该矩阵的最大加权矩形中所有元素的权值和。

输入输出样例

输入 #1复制

复制代码
4
0 -2 -7 0
 9 2 -6 2
-4 1 -4  1 
-1 8  0 -2

输出 #1复制

复制代码
15

说明/提示

样例解释

该矩阵中的最大加权矩形为

复制代码
9  2
-4  1
-1  8

它们的和为 15。

数据范围

对于 100% 的数据,1≤n≤120

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,maxn;
const int N=122;
int a[N][N],sum[N][N];

signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>a[i][j];
			a[i][j]+=a[i][j-1];
			sum[i][j]+=a[i][j]+sum[i-1][j];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			for(int a=1;a<=i;a++){
				for(int b=1;b<=j;b++){
					maxn=max(maxn,sum[i][j]+sum[a-1][b-1]-sum[i][b-1]-sum[a-1][j]);
				}
			}
		}
	}
	cout<<maxn;
	return 0;
}

P1314 [NOIP 2011 提高组] 聪明的质监员

题目描述

小 T 是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有 n 个矿石,从 1 到 n 逐一编号,每个矿石都有自己的重量 wi​ 以及价值 vi​。检验矿产的流程是:

  1. 给定 m 个区间 [li,ri];
  2. 选出一个参数 W;
  3. 对于一个区间 [li,ri],计算矿石在这个区间上的检验值 yi:

yi​=j=li​∑ri​​[wj​≥W]×j=li​∑ri​​[wj​≥W]vj​

其中 j 为矿石编号,[p] 是指示函数,若条件 p 为真返回 1,否则返回 0。

这批矿产的检验结果 y 为各个区间的检验值之和。即:i=1∑m​yi​。

若这批矿产的检验结果与所给标准值 s 相差太多,就需要再去检验另一批矿产。小 T 不想费时间去检验另一批矿产,所以他想通过调整参数 W 的值,让检验结果尽可能的靠近标准值 s,即使得 ∣s−y∣ 最小。请你帮忙求出这个最小值。

输入格式

第一行包含三个整数 n,m,s,分别表示矿石的个数、区间的个数和标准值。

接下来的 n 行,每行两个整数,中间用空格隔开,第 i+1 行表示 i 号矿石的重量 wi​ 和价值 vi​。

接下来的 m 行,表示区间,每行两个整数,中间用空格隔开,第 i+n+1 行表示区间 [li​,ri​] 的两个端点 li​ 和 ri​。注意:不同区间可能重合或相互重叠。

输出格式

一个整数,表示所求的最小值。

输入输出样例

输入 #1复制

复制代码
5 3 15 
1 5 
2 5 
3 5 
4 5 
5 5 
1 5 
2 4 
3 3 

输出 #1复制

复制代码
10

说明/提示

【输入输出样例说明】

当 W 选 4 的时候,三个区间上检验值分别为 20,5,0,这批矿产的检验结果为 25,此时与标准值 s 相差最小为 10。

【数据范围】

对于 10% 的数据,有 1≤n,m≤10;

对于 30% 的数据,有 1≤n,m≤500;

对于 50% 的数据,有 1≤n,m≤5,000;

对于 70% 的数据,有 1≤n,m≤10,000;

对于 100% 的数据,有 1≤n,m≤2×105,0<wi​,vi​≤106,0<s≤1012,1≤li​≤ri​≤n。

实现代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long

ll n, m, s;
ll y, ans;
ll w[200010], v[200010];
ll l[200010], r[200010];
ll qzh1[200010], qzh2[200010];

bool check(ll wq) {
	y = 0;
	memset(qzh1, 0, sizeof(qzh1));  
	memset(qzh2, 0, sizeof(qzh2));
	for (int i = 1; i <= n; i++) {
		if (w[i] > wq)
			qzh1[i] = qzh1[i - 1] + 1, qzh2[i] = qzh2[i - 1] + v[i]; 
		else
			qzh1[i] = qzh1[i - 1], qzh2[i] = qzh2[i - 1];  
	}
	for (int i = 1; i <= m; i++) {
		int rrrr = r[i];
		int llll = l[i];
		y += (qzh1[rrrr] - qzh1[llll - 1]) * (qzh2[rrrr] - qzh2[llll - 1]);
	}
	if (y > s)
		return 1; 
	else
		return 0;
}

int main() {
	cin >> n >> m >> s;
	for (int i = 1; i <= n; i++)
		cin >> w[i] >> v[i];
	for (int i = 1; i <= m; i++)
		cin >> l[i] >> r[i];
	int lll = 1;
	int rrr = 2000010;  
	ans = s;
	while (lll <= rrr) { 
		int mid = lll + (rrr - lll) / 2;  
		if (check(mid))
			lll = mid + 1;
		else
			rrr = mid - 1;
			ans = min(ans, llabs(s - y));
	}
	cout << ans;
}

P2367 语文成绩

题目背景

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

题目描述

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

输入格式

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

第二行有 n 个数,a1​∼an​,代表各个学生的初始成绩。

接下来 p 行,每行有三个数,x,y,z,代表给第 x 个到第 y 个学生每人增加 z 分。

输出格式

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

输入输出样例

输入 #1复制

复制代码
3 2
1 1 1
1 2 1
2 3 1

输出 #1复制

复制代码
2

说明/提示

对于 40% 的数据,有 n≤103。

对于 60% 的数据,有 n≤104。

对于 80% 的数据,有 n≤105。

对于 100% 的数据,有 n≤5×106,p≤n,学生初始成绩 ≤100,z≤100。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+10;
int n,p;
int a[N],b[N];

int main(){
	cin>>n>>p;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		b[i]=a[i]-a[i-1];
	}
	while(p--){
		int x,y,z;
		cin>>x>>y>>z;
		b[x]+=z;
		b[y+1]-=z;
	}
    int min=99999;
	for(int i=1;i<=n;i++){
		a[i]=a[i-1]+b[i];
        if(min>a[i]) min=a[i];
	}
	cout<<min;
	return 0;
}

P3397 地毯

题目背景

加强版

题目描述

在 n×n 的格子上有 m 个地毯。

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

输入格式

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

接下来 m 行,每行两个坐标 (x1​,y1​) 和 (x2​,y2​),代表一块地毯,左上角是 (x1​,y1​),右下角是 (x2​,y2​)。

输出格式

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

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

输入输出样例

输入 #1复制

复制代码
5 3
2 2 3 3
3 3 5 5
1 2 1 4

输出 #1复制

复制代码
0 1 1 1 0
0 1 1 0 0
0 1 2 1 1
0 0 1 1 1
0 0 1 1 1

说明/提示

样例解释

覆盖第一个地毯后:

0 0 0 0 0
0 1 1 0 0
0 1 1 0 0
0 0 0 0 0
0 0 0 0 0

覆盖第一、二个地毯后:

0 0 0 0 0
0 1 1 0 0
0 1 2 1 1
0 0 1 1 1
0 0 1 1 1

覆盖所有地毯后:

0 1 1 1 0
0 1 1 0 0
0 1 2 1 1
0 0 1 1 1
0 0 1 1 1

数据范围

对于 20% 的数据,有 n≤50,m≤100。

对于 100% 的数据,有 n,m≤1000。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int ac[N][N];
int n,m;

int main(){
	cin>>n>>m;
	while(m--){
		int x,y,a,b;
		cin>>x>>y>>a>>b;
		for(int i=x;i<=a;i++){
			for(int j=y;j<=b;j++){
				ac[i][j]++;
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout<<ac[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

P1496 火烧赤壁

题目背景

曹操平定北方以后,公元 208 年,率领大军南下,进攻刘表。他的人马还没有到荆州,刘表已经病死。他的儿子刘琮听到曹军声势浩大,吓破了胆,先派人求降了。

孙权任命周瑜为都督,拨给他三万水军,叫他同刘备协力抵抗曹操。

隆冬的十一月,天气突然回暖,刮起了东南风。

没想到东吴船队离开北岸大约二里距离,前面十条大船突然同时起火。火借风势,风助火威。十条火船,好比十条火龙一样,闯进曹军水寨。那里的船舰,都挤在一起,又躲不开,很快地都烧起来。一眨眼工夫,已经烧成一片火海。

曹操气急败坏的把你找来,要你钻入火海把连环线上着火的船只的长度统计出来!

题目描述

给定每个起火部分的起点和终点,请你求出燃烧位置的长度之和。

输入格式

第一行一个整数,表示起火的信息条数 n。

接下来 n 行,每行两个整数 a,b,表示一个着火位置的起点和终点(注意:左闭右开)。

输出格式

输出一行一个整数表示答案。

输入输出样例

输入 #1复制

复制代码
3
-1 1
5 11
2 9

输出 #1复制

复制代码
11

说明/提示

数据规模与约定

对于全部的测试点,保证 1≤n≤2×104,−231≤a<b<231,且答案小于 231。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
const int N=2e4+10;
int a[N],b[N];

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i]>>b[i];
	}
	sort(a+1,a+1+n);
	sort(b+1,b+1+n);
	int sum=0;
	for(int i=1;i<=n;i++){
		sum+=b[i]-a[i];
		if(i<n){
			if(b[i]>a[i+1]){
				sum-=b[i]-a[i+1];
			}
		}
	}
	cout<<sum;
	return 0;
}
相关推荐
励志的小陈8 小时前
贪吃蛇(C语言实现,API)
c语言·开发语言
Makoto_Kimur8 小时前
java开发面试-AI Coding速成
java·开发语言
laowangpython8 小时前
Gurobi求解器Matlab安装配置教程
开发语言·其他·matlab
wengqidaifeng8 小时前
python启航:1.基础语法知识
开发语言·python
观北海8 小时前
Windows 平台 Python 极简 ORB-SLAM3 Demo,从零实现实时视觉定位
开发语言·python·动态规划
知识浅谈8 小时前
DeepSeek V4 和 GPT-5.5 在同一天发布了??我也很懵,但对比完我悟了
算法
DeepModel8 小时前
通俗易懂讲透 Q-Learning:从零学会强化学习核心算法
人工智能·学习·算法·机器学习
田梓燊8 小时前
力扣:19.删除链表的倒数第 N 个结点
算法·leetcode·链表
handler0110 小时前
从零实现自动化构建:Linux Makefile 完全指南
linux·c++·笔记·学习·自动化