首页 > 编程语言 >蓝桥杯算法集训 - Week1:二分、前缀和、差分算法

蓝桥杯算法集训 - Week1:二分、前缀和、差分算法

时间:2024-03-10 22:35:20浏览次数:35  
标签:int mid 蓝桥 算法 static split import Week1 new

蓝桥杯算法集训 - Week1

本系列随笔用于整理AcWing题单——《蓝桥杯集训·每日一题2024》的系列题型及其对应的算法模板。

一、二分查找

二分算法原理复习参考:二分查找 - Hello 算法

Ⅰ、二分模板

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

Ⅱ、分巧克力

1227. 分巧克力 - AcWing题库

分巧克力

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
	static final int N = 100010;
	static int n, k;
	static int[][] a = new int[N][2];

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] split = br.readLine().split(" ");
		n = Integer.parseInt(split[0]);
		k = Integer.parseInt(split[1]);
		for (int i = 0; i < n; i++) {
			split = br.readLine().split(" ");
			a[i][0] = Integer.parseInt(split[0]);
			a[i][1] = Integer.parseInt(split[1]);
		}
		br.close();
		
		// 二分枚举边长
		int l = 1, r = N;
		while (l < r) {
			int mid = l + (r - l + 1) / 2;
			if (check(mid)) {
				l = mid;
			} else {
				r = mid - 1;
			}
		}
		System.out.println(l);
	}
	
	// 检查是否可以分出k块巧克力
	static boolean check(int mid) {
		int cnt = 0;
		for (int i = 0; i < n; i++) {
			cnt += (a[i][0] / mid) * (a[i][1] / mid);
			if (cnt >= k)
				return true;
		}
		return false;
	}
}

二、前缀和

前缀和原理复习参考:【优选算法】—— 前缀和算法

Ⅰ、前缀和模板

// 一维前缀和
S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]

// 二维前缀和
// S[i, j] = 第i行j列格子左上部分所有元素的和
// 以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

Ⅱ、一维数组的动态和

给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。

请返回 nums 的动态和。

public class Main{
    public int[] runningSum(int[] nums) {
        int[] prefix = new int[nums.length];
        prefix[0] = nums[0];
        for (int i = 1; i < nums.length; ++i) {
            prefix[i] = prefix[i - 1] + nums[i];
        }
        return prefix;
    }
}

Ⅲ、统计子矩阵

4405. 统计子矩阵 - AcWing题库

统计子矩阵

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
	static final int N = 510;
	static int n, m, k;
	static int[][] martix = new int[N][N];
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] split = br.readLine().split(" ");
		n = Integer.parseInt(split[0]);
		m = Integer.parseInt(split[1]);
		k = Integer.parseInt(split[2]);
		for (int i = 1; i <= n; i++) {
			split = br.readLine().split(" ");
			for (int j = 1; j <= m; j++) {
                // 计算矩阵的前缀和数组
				martix[i][j] = martix[i - 1][j] + martix[i][j - 1] - martix[i - 1][j - 1] + Integer.parseInt(split[j - 1]);
			}
		}
		br.close();
		
		long res = 0;
		for (int x1 = 1; i <= n; i++) {
			for (int y1 = 1; j <= m; j++) {
				for (int x2 = x1, x2 <= n; x2++) {
                    for (int y2 = y1, y2 <= m; y2++) {
                        // 枚举每一个二维矩阵的前缀和,符合时s++
                        while (martix[t][j] - martix[s - 1][j] - martix[t][i - 1] + martix[s - 1][i - 1] <= k) s++;
                    }
				}
			}
		}
		System.out.println(res);
	}
}

三、差分

差分算法复习参考:【详解】手撕 一维、二维、三维差分数组原理(附图解,模板,例题分析)

注:差分算法实际为《蓝桥杯集训·每日一题2024》Week 2 内容。但差分与前缀和算法关系很大,互为逆运算,故提前放置于本章。

Ⅰ、差分模板

// 初始化一维差分
B[n] = a[n] - a[n - 1];

// 给区间[l, r]中的每个数加上c:
B[l] += c, B[r + 1] -= c;

// 初始化二维差分
S[i][j] = a[i][j] − a[i−1][j] − a[i][j−1] + a[i−1][j−1];

// 给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c;
S[x2 + 1, y1] -= c;
S[x1, y2 + 1] -= c;
S[x2 + 1, y2 + 1] += c;

Ⅱ、借教室

503. 借教室 - AcWing题库

借教室

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String[] split = reader.readLine().split(" ");
        int n = Integer.parseInt(split[0]);
        int m = Integer.parseInt(split[1]);
        int[] count = new int[n + 1];
        String[] cns = reader.readLine().split(" ");
        for (int i = 1; i <= n; i++) {
            count[i] = Integer.parseInt(cns[i-1]);
        }
        // 初始化差分数组
        for (int i = n ; i >= 1; i--){
            count[i] -= count[i-1];
        }
        int[][] orders = new int[m + 1][3];
        for (int i = 1; i <= m; i++) {
            String[] ods = reader.readLine().split(" ");
            orders[i][0] = Integer.parseInt(ods[0]);
            orders[i][1] = Integer.parseInt(ods[1]);
            orders[i][2] = Integer.parseInt(ods[2]);
        }
        reader.close();
        
        // 二分查找最后符合要求的日期
        int l = 1, r = m;
        while (l < r){
            int mid = (l + r) / 2;
            if (check(count, orders, mid)){
                l = mid + 1;
            }else {
                r = mid;
            }
        }
        if (check(count, orders, r)) {
            System.out.println(0);
        } else {
            System.out.println(-1);
            System.out.println(r);
        }
    }

    // 使用差分算法优化计算效率
    private static boolean check(int[] count, int[][] orders, int mid) {
        // 复制一份差分数组
        long[] copy = new long[count.length];
        for (int i = 1; i < copy.length; i++) {
            copy[i] = count[i];
        }
        // 将第一天到第mid天的教室减去
        for (int i = 1; i <= mid ; i++) {
            // orders[i][0]为第i个订单所需教室数、orders[i][1]为起始天数、orders[i][2]为结束天数
            copy[orders[i][1]] -= orders[i][0];
            if (orders[i][2] != copy.length - 1){
                copy[orders[i][2] + 1] += orders[i][0];
            }
        }
        long res = 0;
        for (int i = 1; i < copy.length; i++) {
            res += copy[i]; // 对差分数组求前缀和获得原始数据
            if (res < 0){
                return false;
            }
        }
        return true;
    }
}

Ⅲ、棋盘

5396. 棋盘 - AcWing题库

棋盘

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class Main {
	static final int N = 2010; 
	static int n, m;
	static int matrix[][] = new int[N][N];
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		PrintWriter pw = new PrintWriter(System.out);
		String[] split = br.readLine().split(" ");
		n = Integer.parseInt(split[0]);
		m = Integer.parseInt(split[1]);
		for (int i = 1; i <= m; i++) {
			split = br.readLine().split(" ");
			// 初始化二维差分
			insert(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]));
		}
		br.close();
		
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				// 求二维前缀和获取结果
				matrix[i][j] += matrix[i - 1][j] + matrix[i][j-1] - matrix[i - 1][j - 1];
			}
		}
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= n; j++) {
				if (matrix[i][j] % 2 == 0) pw.print("0");
				else pw.print("1");;
			}
			pw.print("\n");
		}
		pw.close();
	}
	
	// 对二维差分进行修改的代码模板
	static void insert(int x1, int y1, int x2, int y2) {
		matrix[x1][y1]++;
		matrix[x1][y2 + 1]--;
		matrix[x2 + 1][y1]--;
		matrix[x2 + 1][y2 + 1]++;
	}
}

标签:int,mid,蓝桥,算法,static,split,import,Week1,new
From: https://www.cnblogs.com/tfiyuenlau/p/18065017

相关文章

  • 有限制的 bellman_ford 算法
    题目链接1.有限制的\(Bellman\_Ford\)时间复杂度:\(O(N*M)\)在传统的\(Bellman\_Ford\)中,可以处理边数不大于\(K\)条边的最短距离但我们只要加一条限制(实际上只多了两行代码)就可以实现求恰好等于\(K\)条边的最短距离具体的就在于其核心代码中:for(inti=0;i......
  • 蓝桥杯备赛第一天 分糖果
    #include<bits/stdc++.h>usingnamespacestd;intmain(){//请在此输入您的代码intn;cin>>n;ints=0;inta[101];//getchar();for(inti=0;i<n;i++){cin>>a[i];}while(1){intc[101];for(inti=0;i<n;i++){......
  • 算法题 - Shuffling Machine
    Introduction:Shufflingisaprocedureusedtorandomizeadeckofplayingcards.Becausestandardshufflingtechniquesareseenasweak,andinordertoavoid"insidejobs"whereemployeescollaboratewithgamblersbyperforminginadequatesh......
  • P8599 [蓝桥杯 2013 省 B] 带分数
    题目知识点:全排列加指针划分数组。链接:https://www.luogu.com.cn/problem/P8599#include<iostream>#include<vector>#include<algorithm>#include<math.h>#include<sstream>#include<string>#include<string.h>#include<iomanip>#......
  • 算法学习
    今天复习巩固了深搜和广度搜索,做了几个练习题,其中求细胞数量注意审题,即让我们求连通块的个数。#include<bits/stdc++.h>usingnamespacestd;intx,y;charm[105][105];intsx[4]={-1,0,1,0};//左上右下intsy[4]={0,-1,0,1};voidbfs(inta,intb){ m[a][b]='0'; for(......
  • RIPEMD算法:多功能哈希算法的瑰宝
    一、RIPEMD算法的起源与历程RIPEMD(RACEIntegrityPrimitivesEvaluationMessageDigest)算法是由欧洲研究项目RACE发起,由HansDobbertin、AntoonBosselaers和VincentRijmen共同设计的一种哈希算法。RIPEMD算法最早发布于1996年,旨在提供一种安全、高效的数据完整性验证工具。......
  • 贪心算法
    例题1、硕鼠的交易题目描述ProblemDescription小老鼠准备了M磅的猫粮,准备去和看守仓库的猫做交易,因为仓库里有小老鼠喜欢吃的五香豆。仓库有N个房间;第i个房间有J[i]磅的五香豆,并且需要用F[i]磅的猫粮去交换;老鼠不必交换该房间所有的五香豆,换句话说,它可以用F[i]a%磅的......
  • 基于肤色模型和中值滤波的手部检测算法FPGA实现,包括tb测试文件和MATLAB辅助验证
    1.算法运行效果图预览RTL图:   仿真图:   导入到matlab显示效果如下:   2.算法运行软件版本matlab2022a vivado2019.2 3.算法理论概述      在计算机视觉领域,基于肤色模型和中值滤波的手部检测方法是一种常见的初步定位策略。该方法主要分为......
  • ST算法
    记录9:212024-3-10ST算法其实就是利用倍增的思想去划分区间利用ST算法求RMQ问题(区间最值问题)\(F[i,j]表示数列A在子区间[i,i+2^j-1]里数的最大值F[i,0]=A[i]\)\(F[i,j]=max(F[i,j-1],F[i+2^{j-1},j-1])\)求[l,r]最值的时候求出满足\(2^k<r-l......
  • [NOIP2017 提高组] 小凯的疑惑 / [蓝桥杯 2013 省] 买不到的数目
    这肯定是学证明了,看这篇文章补充一下细节首先,\(m\)的范围应该是\([0,b-1]\)然后,当\(m\)取不同值的时候,\(ma\)%\(b\)一定为不同值(这个性质确实有点奇特,可以记下来)反证,如果\(m_1a\equivm_2a\:(mod\:b)\)且\(0≤m_1<m_2≤b-1\),那么就有\(b|(m_2-m_1)a\),题目给出了\(a,b\)互质,......