当前位置: 首页 > article >正文

蓝桥杯[阶段总结] 二分,前缀和

前言

前些天一直没有发每日一题,是因为我最近在系统学习一些常考算法,时不时自己练一下,这样效率更高。其实之前都是看别人的思路,然后写的题解。虽然在一定程度上可以提升对题目的理解,但这样的效率太低了,为了写一道题的题解,花费大量的时间,到最后对于题目涉及到的算法也只是一知半解。

二分

这里就不过多解释定义,按照我的理解就是,定义左右指针,计算中间值是否符合题意,如果符合的话,就把左指针移动到mid上。否则就将右指针移动到mid-1处。我们来看一道真题:分巧克力。

题目描述

儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
 小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。

  为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:

    1. 形状是正方形,边长是整数  
    2. 大小相同  

例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?

输入

第一行包含两个整数N和K。(1 <= N, K <= 100000)  
以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000) 
输入保证每位小朋友至少能获得一块1x1的巧克力。   

输出

输出切出的正方形巧克力最大可能的边长。
 

解题思路

题目还是很好理解的,这道题也是典型的二分,和我之前讲的冶炼金属很类似。我们将

 所有的边长放在数轴上。如果mid指向的边长切出来的巧克力块数大于等于k的话,那这个位置有可能是答案,就将left移动到此处。反之,如果切出来的巧克力块数小于k,那说明不够分,那就将right移动到mid-1处。

代码实现

import java.util.Scanner;

public class Main {
    private static int nums[][];
    private static int k;

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        nums = new int[n][2];
        k = scan.nextInt();
        for (int i = 0; i < n; i++) {
            nums[i][0] = scan.nextInt();
            nums[i][1] = scan.nextInt();
        }
//        for (int i = 0; i < n; i++) {
//            System.out.println(Arrays.toString(nums[i]));
//        }
        //处理数据
        int left = 1;
        int right = 200050;
        while (left < right) {
            int mid = left + right + 1 >> 1;
            //规定:为true时,移动左指针
            if (check(mid))
                left = mid;
            else right = mid - 1;
        }
        System.out.println(left);
    }

    private static boolean check(int mid) {
        //切割巧克力
        int length = nums.length;
        int total = 0;
        for (int i = 0; i < length; i++) {
            total += (nums[i][0] / mid) * (nums[i][1] / mid);
            if (total >= k)
                return true;
        }

        return false;
    }
}

前缀和

对于一维的来说就简单了,类似数列求和。s[i]就表示从第一个数到第i个数的和。由于是类似数列的,所以就不多解释了。二维前缀和的话,后面遇到题目了再来细讲。

那么我们来看一道基础题。

题目描述

输入一个长度为n的整数序列。
接下来再输入m个询问,每个询问输入一对l,r。
对于每个询问,输出原序列中从第l个数到第r个数的和。

输入格式 

第一行包含两个整数n和m。
第二行包含n个整数,表示整数数列。
接下来m行,每行包含两个整数l和r,表示一个询问的区间范围。

输出格式 

共m行,每行输出一个询问的结果。

数据范围 


1<l<r<n,
1<n,m<100000,
—1000<数列中元素的值<1000

代码实现

上代码

 

import java.io.IOException;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int m = scan.nextInt();
        int[] nums = new int[n + 100];
        int[] s = new int[n + 100];
        for (int i = 1; i <= n; i++) {
            nums[i] = scan.nextInt();
        }
        //计算前缀和
        for (int i = 1; i <= n; i++) {
            s[i] = s[i - 1] + nums[i];
        }
        int l;
        int r;
        while(m-->0){
            l= scan.nextInt();
            r= scan.nextInt();
            System.out.println(s[r]-s[l-1]);
        }
    }
}



//这里我自定义了一个输入类,用于快读的。

class Scanner {
    private BufferedReader bf;
    private StreamTokenizer st;

    public Scanner(InputStream inputStream) {
        bf = new BufferedReader(new InputStreamReader(inputStream));
        st = new StreamTokenizer(bf);
    }

    public int nextInt() throws IOException {
        st.nextToken();
        return (int) st.nval;
    }

    public String nextLine() throws IOException {
        return bf.readLine();
    }
}


http://www.kler.cn/a/588349.html

相关文章:

  • 华为云容器引擎应用场景
  • 游戏成瘾与学习动力激发研究——多巴胺脉冲式释放与奖赏预测误差机制的神经科学解析
  • ccf3501密码
  • 计算机操作系统进程(4)
  • 【网络】什么是反向代理Reverse Proxies?
  • matlab中如何集成使用python
  • Python中在类中创建对象
  • 基于Spring Boot的航司互售系统
  • Java中队列(Queue)和列表(List)的区别
  • 基于ssm+vue汽车租赁系统
  • 量化交易学习笔记02:双均线策略
  • java项目之基于ssm的药店药品信息管理系统(源码+文档)
  • TCP/IP协议中三次握手(Three-way Handshake)与四次挥手(Four-way Wave)
  • 面试系列|蚂蚁金服技术面【1】
  • C++那些事儿:访问控制与友元函数的奇妙冒险
  • C语言 —— 此去经年梦浪荡魂音 - 深入理解指针(卷一)
  • Vue开发者工具(VueDevtools)下载与安装
  • 区跨链知识和概念
  • C++|空指针nullptr
  • Ubuntu24.10编译Android12源码并运行于模拟器中