noip数据结构与算法 之 基础小算法 一维前缀和维护

noip数据结构与算法 之 基础小算法 一维前缀和维护

###一维前缀和维护是一种基础的小算法,该算法用我们所熟知的数列求和方式优化我们的某些查询操作,是一种动态规划的思想。
###这里为介绍一维前缀和维护问题,我们来思考这个最简单的问题:

问题描述:
已知n个数的数列a,有m次询问,每次询问给定l,r两个数,求 $a_l $到 a r a_r ar 内所有数的和。注意l到r的区间包含 a l a_l al a r a_r ar 两个数。
输入数据:
第一行n和m,接下来一行有n个数,表示数列a,接下来有m行,每行有两个数l,r,详细解释参考问题描述。
输出数据:
m行,每行一个求和解。
输入样例:
5 2
1 2 3 4 5
2 4
3 5
输出样例:
9
12
数据范围:
0 &lt; N , M ≤ 100000 0 \lt N,M \le 100000 0<N,M100000
a i a_i ai 是int范围内的任意整数
###对于这个问题而言,我们一开始想到的思路是对于每一次查询操作都遍历一遍我们的数组进行求和,这样的操作每一次都会遍历数组,是O(nm)的做法,而对于题目的数据量,这样一定会超时,于是我们要思考有没有更加优化的解。
###先考虑暴力的情况,我们对于每一次查询操作,都遍历一遍数组,我们会发现,当我计算了某一区间值的时候,我计算其他区间,会重复计算某些值,我是否可以用一种方式,把这种重复利用起来。
###于是我们想到了初中学过的前n项和问题。当我知道前r项和与前l-1项和,我是否就能求出从l到r的区间和?思考一下这个过程。前r项和里面包含了前l-1项和,所以做一个减法就能求出l到r的区间和。那么问题就到了我们如何求前n项和,这个问题更加简单,我们只需要遍历一次数组就可以求到这个前n项和的数组了,假设我们原数组是a,前n项和的数组是s,那么我们只需要 s 1 = a 1 s_1=a_1 s1=a1之后维护动规方程 s i = s i − 1 + a i ( i &gt; 1 ) s_i=s_{i-1}+a_i(i&gt;1) si=si1+ai(i>1)即可。
###那么问题迎刃而解,我们分析一下新解法的复杂度,求出s数组需要遍历一遍原数组,所以是O(n)的复杂度,对于每一次查询操作我们只需要做一次减法,所以是O(1)的复杂度,一共有m次,所以是O(m)的查询,最后的结果就是O(n+m)的时间复杂度。
###以上就是关于一维的前缀和维护问题和解法的介绍。

我的代码如下:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <cmath>
#include <algorithm>
using namespace std;

const int MAXN=1000010;

int n,m,a[MAXN];

//读入优化 
int read(){
	char ch=getchar();
	bool fl=0;
	int r=0;
	if(ch=='-'){
		fl=1;
		ch=getchar();
	} 
	while(ch>='0'&&ch<='9'){
		r*=10;
		r+=ch-'0';
		ch=getchar();
	}
	return fl?-r:r; 
}

//输出优化 
void write(int x){
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9){
		write(x/10);
	}
	putchar(x%10+'0');
}

int main(){
	freopen("in.txt","r",stdin);
	freopen("std.txt","w",stdout);
	n=read();
	m=read();
	a[0]=read();
	for(int i=1;i<n;++i){
		a[i]=read();
		a[i]+=a[i-1];//前n项和求法,O(n)复杂度 
	}
	for(int i=0;i<m;++i){
		int l,r;
		l=read();
		r=read();
		if(l==1){
			write(a[r-1]);//输出结果,单次O(1),总共O(m) 
		}else{
			write(a[r-1]-a[l-2]);//隐含的数组下标越界问题,在我写二维前缀和的时候发现的 
		}
		putchar('\n');
	}
	return 0;
} 
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值