蓝桥杯--前缀和1

直接贴道模板题

AcWing 795. 前缀和

原题链接

题意:求出序列第l位至第r位的和

前缀和也是一种避免遍历造成时间浪费的方法,可以用O(1)的时间求出一个区间和,在构造序列时可以顺便构造前缀和序列,后续直接使用,实现意义即是前缀和序列的第 i 位的值等于原序列前 i 位的和,特殊题型中可能会有变化,不过大体思路不变

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Scanner;
import java.util.Vector;

public class Main {
	static Scanner tab = new Scanner(System.in);
	static BufferedWriter tabb = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N = 110000;

	static int n;
	static int a[]=new int [N];
	static int b[]=new int [N];

	public static void main(String[] args) throws IOException {
		n=tab.nextInt();
		int m=tab.nextInt();
		for(int i=1;i<=n;i++) {
			a[i]=tab.nextInt();
			b[i]=a[i]+b[i-1];
		}
		while(m-->0) {
			int l=tab.nextInt();
			int r=tab.nextInt();
			System.out.println(b[r]-b[l]+a[l]);
		}

	}
}


AcWing 796. 子矩阵的和

原题链接

题意:给出矩阵,求出两个坐标构成的矩形内值的和

从这题开始遇到的都是二维前缀和,和一维差不多,不过由于是二维,无论是构造还是计算中都要考虑到重复计算的问题,类似高中的集合知识,计算两个集合的并集时,要用两个集合相加并减去交集部分,反之减去并集的话也要加上交集的部分
此题中可以用右下坐标的前缀和减去上和左两方向的多余值,由于重复减去了左上值两次,最后再加上一个左上的前缀和值

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Scanner;
import java.util.Vector;

public class Main {
	static Scanner tab = new Scanner(System.in);
	static BufferedWriter tabb = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N = 1100;

	static int a[][]=new int [N][N];
	static int b[][]=new int [N][N];

	public static void main(String[] args) throws IOException {
		int n=tab.nextInt();
		int m=tab.nextInt();
		int q=tab.nextInt();
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				a[i][j]=tab.nextInt();
				b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a[i][j];
			}
		}
		while(q-->0) {
			int x1=tab.nextInt();
			int y1=tab.nextInt();
			int x2=tab.nextInt();
			int y2=tab.nextInt();
			int sum=b[x2][y2]-b[x2][y1-1]-b[x1-1][y2]+b[x1-1][y1-1];
			System.out.println(sum);
		}

	}
}


AcWing 99. 激光炸弹

原题链接

题意:给出目标在矩阵中的坐标及权值,给出炸弹波及范围,求出炸弹能够覆盖位置权值的最大值

二维区间和问题,很直观的联系到前缀和。构造前缀和序列,以炸弹范围r为矩阵边长求区间和即可。需要注意的是题中默认是将目标放在矩阵的交点上而并非是格中,可以将坐标整体+1,既能实现目标从点转移至格,同时也方便后续前缀和序列的边界处理。

import java.io.*;
import java.util.*;

public class Main {
	static Scanner tab = new Scanner(System.in);
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N = 5010;
	
	static int s[][]=new int [N][N];
	
	
	public static void main(String[] args) throws IOException {
		int n,m;//定义矩形长宽
		int cnt=tab.nextInt();
		int r=tab.nextInt();
		r=Math.min(r, 5001);
		n=r;
		m=r;
		
		while(cnt-->0) {
			int x=tab.nextInt();
			int y=tab.nextInt();
			int w=tab.nextInt();
			x++;//实现目标从点转移到格位,同时初始位置设为1简化前缀和的构造
			y++;
			s[x][y]+=w;
			n=Math.max(n, x);
			m=Math.max(m, y);
		}
		
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
			}
		}
		
		int res=0;
		for(int i=r;i<=n;i++) {
			for(int j=r;j<=m;j++) {
				res=Math.max(res, s[i][j]-s[i-r][j]-s[i][j-r]+s[i - r][j - r]);
			}
		}
		System.out.println(res);
		
	}
}

注意的是二维数组如果开的过大的话会爆掉,最好定义为全局变量,c或c+同理


AcWing 1230. K倍区间

原题链接

题意:给出序列,求出序列中区间和是k的倍数的区间有多少个

首先区间和肯定会用到前缀和思想,实现前缀和后如果暴力枚举还是会超时,于是分析一下题意,可以得出以第 i 位为右端点的前缀和Si左侧共有(0~i-1)i 种左端点t,每计算一个以Si为右端点的区间值即是Si减去St的值是否为k的倍数,换句话来说就是Si mod k = St mod k 即是此区间符合条件。
这里可以使用类似递推的思想,从1至n枚举右端点,建立一个cnt数组,将下标m定义为mod k,来记录mod k = m的区间数。由于右端点从左至右枚举,cnt数组会随着计算实时变化,后续计算的区间也不会发生遗漏。


import java.io.*;
import java.util.*;

public class Main {
	static Scanner tab = new Scanner(System.in);
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N = 100010;
	
	
	public static void main(String[] args) throws IOException {
		int n=tab.nextInt();
		int k=tab.nextInt();
		long a[]=new long [N];//int会爆
		long cnt[]=new long [N];//记录mod k区间数
		for(int i=1;i<=n;i++) {//构造前缀和
			a[i]=tab.nextLong();
			a[i]=a[i-1]+a[i];
		}
		long res=0;
		cnt[0]=1;//初始化
		for(int i=1;i<=n;i++) {
			res+=cnt[(int)(a[i]%k)];
			cnt[(int)(a[i]%k)]++;
			//核心代码
			//一定要首先计算数量,再将cnt更新
			//如果先更新cnt会出现一个Si-Si的结果
			//而前缀和不应存在这种情况
		}
		System.out.println(res);
	}
}

前缀和题量不多 后续再补


打团队赛都凑不出队友来 真是可悲

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值