acwing2

1.前缀差分
一维前缀和
原数组a[a1,a2,…an]
前缀和:Si=a1+a2+a3+…+ai(其实是一个公式),必须让下标从1开始,前i个数的和
Si是进行for循环,快速求出一个数组中一段数的和S[r]-s[l-1]求出l到r的和
s[0]=0;
for(int i=1;i<n;i++)
{
s[i]=s[i-1]+a[i];
}

					import java.io.BufferedInputStream;
					import java.io.InputStreamReader;
					import java.util.Scanner;
					
					public class test01 {
					    public static void main(String[] args) {
					        Scanner in = new Scanner(new BufferedInputStream(System.in));
					        System.out.println("输入数组大小");
					        int n=in.nextInt();//数组的长度
					        int[] arr = new int[n+1];
					        //输入数组元素
					        for (int i=1;i<=n;i++){
					            System.out.println("数组元素"+i);
					            arr[i]=in.nextInt();
					        }
					        int[] s= new int[n+1];
					        s[0]=0;
					        for(int i=1;i<=n;i++){
					            s[i]=s[i-1]+arr[i];
					            System.out.println(s[i]);
					        }
					        int l=in.nextInt();//这个是左边界
					        int r=in.nextInt();//这个是右边界
					        System.out.println(s[r]-s[l-1]);
					    }
					}

二维前缀和
S【i】[j]就是i之前j之前的所有元素的和,是从左顶点a【0】【0】到a【i】【j】的一个矩形和
Sx2,y2-Sx2,y1-1-Sx-1,y2+Sx-1,y-1 求两点之间的和
Sij=si-1,j+si,j-1-si-1,j-1+aij
package acwing基础算法;
在这里插入图片描述
这里就是(2,2)和(3,3),因为我们要看的是(2,2)位置的这个元素和(3,3)位置这个元素之间的部分和
这是个元素位置,不是一个点,这里的y1-1,x-1也是因为我们要减去的是(3,1)和(1,3)位置的元素,最终加的是(1,1)
其实归根到底的原因是因为这个地方的(2,2),如果这里按得是(1,1)的话就不需要进行-1的操作,这里可以这样简单记忆,就是只要是关于x1,y1的相关操作都去-1

		import java.io.BufferedInputStream;
		import java.util.Scanner;
		
		public class PreMultiSum {
		    private static final int N = 1010;
		    public static void main(String[] args) {
		        Scanner in = new Scanner(new BufferedInputStream(System.in));
		        //n行
		        int n = in.nextInt();
		        //m列
		        int m = in.nextInt();
		        int q = in.nextInt();
		        int [][]a = new int[N][N];
		        int [][]s = new int[N][N];
		        //二维数组赋值
		        for(int i=1;i<=n;i++)
		            for(int j=1;j<=m;j++){
		                a[i][j] = in.nextInt();
		            }
		        //求完整和
		        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]+a[i][j];
		            }
		        //求部分和
		        while(q--!=0){
		            int x1=in.nextInt(),y1=in.nextInt(),x2=in.nextInt(),y2=in.nextInt();
		            System.out.println(s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]);
		        }
		    }
		}

差分:
a1,a2,…an
构造b1,b2…bn使得ai=b1+b2+…+bi
差分:只要有b数组可以在O(n)的时间内得到a数组,b的前缀和就是a数组
如果我们想要ai+c,所有的ai都加一个c,需要O(n)遍历一遍
但是如果有了b数组,只需要在b1+c,所有的ai都包含b1,b1加c,其他的ai也一定会加c
想要在某一个范围[l,r]内+c,其余地方不加c的话,只需要bl+c,br+1 -c ,c一加一减局可以抵消掉
因为b数组的存在,这种操作的时间复杂度就是O(1)

输入一个长度为n的整数序列
接下来输入m个操作,每个操作包含三个整数l,r,c,表示将序列中[l,r]之间的每个数加上c
输入:整数n--数组个数
		  整数m--m次操作
		  整数l--从l开始
		  整数r--到r结束
		  整数c--添加的元素	

假定初始的时候a数组全部为0,那么b数组也全部为0,假定是进行n次插入操作
在原始的【1,1】区间加上a1,在原始的【2,2】区间加上a2,。。。

	import java.io.BufferedInputStream;
	import java.util.Scanner;
	
	public class test02 {
	    private static final int N=100010;
	    public static void insert(int l,int r,int x,int []b){
	        b[l]+=x;//a=1 2 2 1 2 1   insert(i,i,a[i],b); 1===n
	        b[r+1]-=x;//b1=1 b2=-1   b2=-1+2=1 b3=-2 b3=-2+2=0 b4=-2 b4=-2+1=-1 b5=-1 b5=-1+2=1 b6=-2 b6=-1 b7=-1
	    }//b1=1,b2=1,b3=0,b4=-1,b5=1,b6=-1,b7=-1
	//插入之后又减去相当于没插入,但是累加的时候可以获得最后一个
	//a2是b1+b2的和,b1添加的a1在b1加上又在b2减去所以相当于没加,a2添加在b2上正好累加,(求a3的时候又会将a2减去正合适)
	    public static void main(String[] args) {
	        Scanner in = new Scanner(new BufferedInputStream(System.in));
	        int n = in.nextInt(),m = in.nextInt();
	        int[] a = new int[N];
	        int[] b = new int[N];
	        //给a数组赋值
	        for(int i=1;i<=n;i++){
	            a[i]=in.nextInt();
	        }
	        //按a数组构造b数组
	        for(int i=1;i<=n;i++){
	            insert(i,i,a[i],b);
	        }
	        //多次输入,给出每次修改的差分数列后的结果
	        while(m--!=0){
	            int l=in.nextInt(),r=in.nextInt(),c=in.nextInt();
	            insert(l,r,c,b);
	
	        }
	        //重新求和数列同时注意b[0]等于0
	        for(int i=1;i<=n;i++){
	            b[i]+=b[i-1];
	        }
	        for(int i=1;i<=n;i++){
	            System.out.print(b[i]+" ");
	        }
	    }
	}

二维差分
差分矩阵bij的构造:
满足原矩阵是差分矩阵的和就可以了
bx1,y1 +=c//将点(x,y)下的所有的点都加上c了肯定要减去
bx2+1,y1 -=c//将最下面的线往下减去c
bx1,y2+1-=c//将最右边的下往下减去c
bx2+1,y2+1+=c;//因为减去了两次所以要再加上

	import javafx.scene.transform.Scale;
	
	import java.io.BufferedInputStream;
	import java.util.Scanner;
	
	public class test03 {
	    private static final int N=100010;
	    public static void main(String[] args) {
	        Scanner in = new Scanner(new BufferedInputStream(System.in));
	        int n=in.nextInt();
	        int m=in.nextInt();
	        int q=in.nextInt();
	        int[][] a = new int[N][N];
	        int[][] b=new int[N][N];
	        for(int i=1;i<=n;i++)
	        {
	            for(int j=1;j<=m;j++){
	                a[i][j]=in.nextInt();
	            }
	        }
	        //把a矩阵的每个数插入空的b中去,和一维的是差不多的操作,插入到b中,形成差分矩阵
	        for(int i=1;i<=n;i++) {
	            for (int j = 1; j <= m; j++) {
	                insert(i,j,i,j,a[i][j],b);
	            }
	        }
	        while(q--!=0){
	            int x1=in.nextInt();
	            int y1=in.nextInt();
	            int x2=in.nextInt();
	            int y2=in.nextInt();
	            int c=in.nextInt();
	            insert(x1,y1,x2,y2,c,b);
	        }
	        for(int i=1;i<=n;i++) {
	            for (int j = 1; j <= m; j++) {
	                b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1];
	                System.out.println(b[i][j]);
	            }
	        }
	
	    }
	    public static void insert(int x1,int y1,int x2, int y2 ,int c,int[][] b){
	        b[x1][y1]+=c;
	        b[x2+1][y1]-=c;
	        b[x1][y2+1]-=c;
	        b[x2+1][y2+1]+=c;
	
	    }
	}

超时了,我看的下面这个链接的操作,输入流才不超时的
https://www.cnblogs.com/mingustc/p/14619442.html
贴一下大佬的代码

	package acwing基础算法;
	
	import java.io.*;
	import java.util.Scanner;
	
	public class DifferenceMulti {
	
	    private static final int N=1010;
	
	    public static void insert(int x1,int y1,int x2,int y2,int c,int [][]b){
	           b[x1][y1]+=c;
	           b[x2+1][y1]-=c;
	           b[x1][y2+1]-=c;
	           b[x2+1][y2+1]+=c;
	    }
	    public static void main(String[] args) throws IOException {
	
	
	        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
	   
	        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
	        String[] s1 = reader.readLine().split(" ");  //将读入的字符串按照“ ”空格进行分割,获取一个个单个的字符
	        int n = Integer.parseInt(s1[0]),m = Integer.parseInt(s1[1]);//将字符强制转换为int型数据
	        int q = Integer.parseInt(s1[2]);
	        int [][]a = new int[N][N];
	        int [][]b = new int[N][N];
	
	
	        for(int i=1;i<=n;i++) {
	            String[] s2 = reader.readLine().split(" ");
	            for (int j = 1; j <= m; j++) {
	                a[i][j] = Integer.parseInt(s2[j - 1]);
	                insert(i, j, i, j, a[i][j], b);
	            }
	        }
	
	        while(q--!=0){
	            String[] s3 = reader.readLine().split(" ");
	            int x1 = Integer.parseInt(s3[0]),
	            y1 = Integer.parseInt(s3[1]),
	            x2 = Integer.parseInt(s3[2]),
	            y2 = Integer.parseInt(s3[3]),
	            c = Integer.parseInt(s3[4]);
	            insert(x1,y1,x2,y2,c,b);
	        }
	
	        for(int i=1;i<=n;i++) {
	            for (int j = 1; j <= m; j++) {
	                b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
	                //输出
	                writer.write(b[i][j] + " ");
	
	            }
	            writer.write("\n");
	        }
	        writer.flush();
	        reader.close();
	        writer.close();
	    }
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值