【蓝桥杯】练习题目合集(自用)-1

题单

  1. 数组:洛谷题单 - 数组 😎
    image
  2. 队列 🎉
  3. 优先队列😭
  4. 栈 🙀
  5. 二叉树 😎 (大多和搜索(BFS、DFS)、路径计算、动态规划有关,下面是二叉树概念题)

同余方程组

消失的蓝宝 20553

解析参考 同余方程组章节

点击查看代码
//法一
public class Main {
    public static void main(String[] args) {
      System.out.print(20240413L*20250411L-20250412L);
    }
}

//法二
public class Main {
    public static void main(String[] args) {
      long x = 20250412L;
      long y = 20240413L;
      long lcm = x * y / gcd(x, y);
      System.out.print(lcm - x - y);
    }
    public static long gcd(long a, long b){
      return b == 0 ? a : gcd(b, a % b);
    }
}

//法三
import java.math.BigInteger;
public class Main {
    public static void main(String[] args) {
      long ans = 20230414L;
      long gongbeishu = 1L;
      long x = 20240413L;
      long y = 20250412L;
      gongbeishu = lcm(gongbeishu, x);
      while(ans % y!= 9999L){
        ans += gongbeishu;
      }
      System.out.print(ans);
    }
    public static long lcm(long a, long b){
      long gcd = BigInteger.valueOf(a).gcd(BigInteger.valueOf(b)).longValue();// 最大公约数
      return a / gcd * b;//最小公倍数
    }
}

数学问题

货物摆放 1463

求大数的所有因子,然后找到大数的i*j*k的所有分解方式。

圆弧的数学问题【×】

移动距离 20558

image

public class Main {
    public static void main(String[] args) {
      double x = 233;
      double y = 666;
      double r = Math.sqrt(x*x + y*y);
      double theta = Math.atan2(y, x);
      double ans = r + r * theta;
      System.out.print(Math.round(ans));
    }
}

这个哥们推理了为啥一次【右、弧】是最短的。
image

客流量上限 20550【×】

image

TODO:没看明白答案

大佬解析:
image

幻方矩阵

P2615 [NOIP 2015 提高组] 神奇的幻方

点击查看代码
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[][] arr = new int[n + 1][n + 1];
        arr[1][n/2 + 1] = 1;
        int i = 1, j = n/2 + 1;//记录k = 1时的位置
        for(int k = 2;k <= n*n;k++){
            if(i == 1 && j != n){
                arr[n][j + 1] = k;
                i = n;
                j = j + 1;
            }else if(i != 1 && j == n){
                arr[i - 1][1] = k;
                i -= 1;
                j = 1;
            }else if(i == 1 && j == n){
                arr[i + 1][j] = k;
                i += 1;
            }else if(i != 1 && j != n){
                if(arr[i - 1][j + 1] == 0) {
                    arr[i - 1][j + 1] = k;
                    i -= 1;
                    j += 1;
                }
                else{
                    arr[i + 1][j] = k;
                    i += 1;
                }
            }
        }
        for(i = 1;i <= n;i++){
            for(j = 1;j <= n;j++)
                System.out.print(arr[i][j] + " ");
            System.out.println();
        }
    }
}

模拟

蛇形矩阵

P5731 【深基5.习6】蛇形方阵

点击查看代码
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[][] arr = new int[n+2][n+2];
        int x = 1, y = 1;
        arr[1][1] = 1;
        int i = 2;
        while(i <= n * n){
            //最开始从arr[1][2]进行赋值,arr[1][1]需要在while外面先赋值
            while(y + 1 <= n && arr[x][y + 1] == 0){    
                y++;
                arr[x][y] = i;
                i++;
            }
            while(x + 1 <= n && arr[x + 1][y] == 0){
                x++;
                arr[x][y] = i;
                i++;
            }
            while(y - 1 >= 1 && arr[x][y - 1] == 0){
                y--;
                arr[x][y] = i;
                i++;
            }
            while(x - 1 >= 1 && arr[x - 1][y] == 0){
                x--;
                arr[x][y] = i;
                i++;
            }
        }
        for(i = 1;i <= n;i++){
            for(int j = 1;j <= n;j++){
                System.out.printf("%3d",arr[i][j]);
            }
            System.out.println();
        }
    }
}

杨辉三角

P5732 【深基5.习7】杨辉三角

点击查看代码
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[][] arr = new int[n + 1][n + 1];
        if(n == 1){
            System.out.print(1);
            return;
        }
        arr[1][1] = 1;
        for(int i = 2;i <= n;i++){
            for(int j = 1;j <= i;j++){
                if(j == 1) arr[i][1] = 1;//左端
                else if(j == i) arr[i][i] = 1;//右端
                else arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];//中间
            }
        }
        for(int i = 1;i <= n;i++){
            for(int j = 1;j <= i;j++)
                System.out.print(arr[i][j] + " ");
            System.out.println();
        }
    }
}

数组越界问题

P1789 【Mc生存】插火把

点击查看代码
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();//方阵
        int m = sc.nextInt();//火把
        int k = sc.nextInt();//萤石
        int[][] arr = new int[n + 4][n + 4];//周围空出来两层防止越界
        for(int i = 2;i <= m + 1;i++){//火把
            int x = sc.nextInt() + 1;//由于开辟的方阵长宽范围都是[2, n+1],因此需要将输入的火把、萤石位置向右下方移动一格
            int y = sc.nextInt() + 1;
            arr[x][y] = 1;
            arr[x - 1][y] = 1; arr[x - 2][y] = 1;//左1、2
            arr[x + 1][y] = 1; arr[x + 2][y] = 1;//右1、2
            arr[x][y - 1] = 1; arr[x][y - 2] = 1;//上1、2
            arr[x][y + 1] = 1; arr[x][y + 2] = 1;//下1、2
            arr[x - 1][y - 1] = 1; arr[x - 1][y + 1] = 1;//左上,右上
            arr[x + 1][y - 1] = 1; arr[x + 1][y + 1] = 1;//左下,右下
        }
        for(int i = 2; i <= k + 1;i++){//萤石
            int x = sc.nextInt() + 1;
            int y = sc.nextInt() + 1;
            for(int j = x-2;j <= x+2;j++)
                for(int p = y-2;p <= y+2;p++)
                    arr[j][p] = 1;
        }
        int ans = 0;
        for(int i = 2;i <= n + 1;i++){
            for(int j = 2;j <= n + 1;j++){
                if(arr[i][j] == 0) ans++;
                // System.out.print(arr[i][j]);
            }
            // System.out.println();
        }
        System.out.print(ans);
    }
}

字符串压缩技术

P1320 压缩技术(续集版)

点击查看代码
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int n = s.length();
        System.out.print(n);
        for(int i = 1;i < n;i++)
            s += sc.next();
        int sum = n * n;
        int x = 0;
        int i = 0;
        while(i < sum){
            while(s.charAt(i) == '0'){
                x++;
                i++;
                if(i == sum) break;
            }
            System.out.print(" " + x);
            if(i == sum) return;
            x = 0;
            while(s.charAt(i) == '1'){
                x++;
                i++;
                if(i == sum) break;
            }
            System.out.print(" " + x);
            x = 0;
        }
    }
}
待完善的代码(测试用例能过,提交过不了,需要数据看看)
import java.util.*;

public class Main{
    public static void main(String[] args){
      Scanner sc = new Scanner(System.in);
        String s = sc.next();
        int n = s.length();
        System.out.print(n);
        for(int i = 1;i < n;i++)
            s += sc.next();
        char prev = s.charAt(0);
        int count = 1;

        for(int i = 1; i < s.length(); i++){
            if(s.charAt(i) == prev){
                count++;
            }else{
                System.out.print(" " + count);
                count = 1;
                prev = s.charAt(i);
            }
        }

        System.out.print(" " + count);
    }
}

矩阵旋转、水平翻转

P1205 [USACO1.2] 方块转换 Transformations

写麻烦了,旋转90°可以复用,180°、270°不需要重写来着,懒得改了

点击查看代码
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        char[][] start = new char[n][n];
        char[][] end = new char[n][n];
        char[] arr = new char[n * n];
        int sum = 0;
        for(int i = 0;i < n;i++){
            String s = sc.next();
            for(int j = 0;j < n;j++){
                start[i][j] = s.charAt(j);
                arr[sum++] = s.charAt(j);
            }
        }
        for(int i = 0;i < n;i++){
            String s = sc.next();
            for(int j = 0;j < n;j++)
                end[i][j] = s.charAt(j);
        }
        if(judge(end, rotate90(n, arr), n)) System.out.print(1);
        else if(judge(end, rotate180(n, arr), n)) System.out.print(2);
        else if(judge(end, rotate270(n, arr), n)) System.out.print(3);
        else if(judge(end, flip_horizontal(n, start), n)) System.out.print(4);
        else if(judge(end, flip_horizontal90(n, start), n)) System.out.print(5);
        else if(judge(end, flip_horizontal180(n, start), n)) System.out.print(5);
        else if(judge(end, flip_horizontal270(n, start), n)) System.out.print(5);
        else if(judge(end, start, n)) System.out.print(6);
        else System.out.print(7);
            
    }
    //旋转90°
    public static char[][] rotate90(int n, char[] arr){
        char[][] c = new char[n][n];
        int sum = 0;
        for(int i = n - 1;i >= 0;i--)
            for(int j = 0;j < n;j++)
                c[j][i] = arr[sum++];//02 12 22 01 11 21 00 10 20
        return c;
    }
    //旋转180°(旋转90° * 2)
    public static char[][] rotate180(int n,char[] arr){
        char[][] c = new char[n][n];
        int sum = 0;
        for(int i = n -1;i >= 0;i--)
            for(int j = n - 1;j >= 0;j--)
                c[i][j] = arr[sum++];//22 21 20 12 11 10 02 01 00
        return c;
    }
    //旋转270°(旋转90° * 3)
    public static char[][] rotate270(int n, char[] arr){
        char[][] c = new char[n][n];
        int sum = 0;
        for(int i = 0;i < n;i++)
            for(int j = n - 1;j >= 0;j--)
                c[j][i] = arr[sum++];//20 10 00 21 11 01 22 12 02
        return c;
    }
    //水平翻转
    public static char[][] flip_horizontal(int n, char[][] start){
        char[][] c = new char[n][n];
        int sum = 0;
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                c[i][j] = start[i][n-1-j];
        return c;
    }
    //水平翻转 + 90°
    public static char[][] flip_horizontal90(int n, char[][] start){
        char[][] c = flip_horizontal(n, start);//翻转
        char[] arr = toOneDimension(n,c);
        char[][] c2 = rotate90(n, arr);
        return c2;
    }
    //水平翻转 + 180°
    public static char[][] flip_horizontal180(int n, char[][] start){
        char[][] c = flip_horizontal(n, start);//翻转
        char[] arr = toOneDimension(n,c);
        char[][] c2 = rotate180(n, arr);
        return c2;
    }
    //水平翻转 + 270°
    public static char[][] flip_horizontal270(int n, char[][] start){
        char[][] c = flip_horizontal(n, start);//翻转
        char[] arr = toOneDimension(n,c);
        char[][] c2 = rotate270(n, arr);
        return c2;
    }
    //二维数组转一维
    public static char[] toOneDimension(int n, char[][] c){
        char[] arr = new char[n * n];
        int sum = 0;
        for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                arr[sum++] = c[i][j];
        return arr;
    }
    //判断两数组是否相等
    public static boolean judge(char[][] end, char[][] c, int n){
        boolean b = true;
        for(int i = 0;i < n;i++)
             for(int j = 0;j < n;j++)
                if(end[i][j] != c[i][j]){
                    b = false;
                    break;
                }
        return b;
    }
}

image

完美数对【枚举】

完美数对 20109

点击查看代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = (int)(1e6+1);
        int n = sc.nextInt();
        int[] a = new int[n];//能力值
        int[] count = new int[N];
        int maxA = 0, sum = 0;
        for(int i = 0;i < n;i++){
          a[i] = sc.nextInt();
          count[a[i]]++;//记录能力值a[i]的个数
          maxA = Math.max(maxA, a[i]);//取a[i]的最大值
        }
        for(int i = 1;i <= maxA;i++){
          for(int j = 1;j <= count[i];j++){//j <= count[i],i至少出现j次
            if(i <= count[j]) sum++;//j至少出现i次
          }
        }
        System.out.print(sum);
        sc.close();
    }
}

小桥的冒险【贪心】

点击查看代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int x, max, ans;
        while(n-- > 0){
            x = sc.nextInt();
            max = sc.nextInt();
            ans = 0;
            while(x > 0){
                x  = (x >=  max) ? x - max : x - 1;
                ans++;
            }
            System.out.println(ans);
        }
    }
}

经典问题

队列

P1996 约瑟夫问题:模拟循环队列

点击查看代码
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        Queue<Integer> q = new LinkedList<>();
        for(int i = 1;i <= n;i++) q.offer(i);//添加编号
        while(q.size() > 0){
            for(int i = 1;i < m;i++){
                q.offer(q.peek());//将报数不是m的编号从队头放到队尾,这样就可以模拟循环队列
                q.poll();
            }
            System.out.print(q.peek() + " ");
            q.poll();
        }
    }
}

栈

P1449 后缀表达式

需要注意c[i] - '0' + 2 != c[i] + 2

点击查看代码
// 操作栈: + * -
// 数字栈:3 5 2 7
// 计算顺序:- 2 5;* 3;+ 7;@
// 遇到数字,完整操作数直接入栈,遇到操作符,弹出栈顶两个数字进行运算,然后得到结果继续入栈。
// 反复弹栈、入栈直至遇到结束符@

//记得考虑操作数为负数的情况
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        char[] c = s.toCharArray();
        int num = 0;
        int i = 0;
        Deque<Integer> stack = new ArrayDeque<>();//操作数
        int a = 0,b = 0;
        while(c[i] != '@'){
            if(Character.isDigit(c[i])){
                num = c[i] - '0';
                while(c[++i] != '.'){
                    num = num * 10 + (c[i] - '0');//此处一定要记得c[i] - '0',不然加法会出bug
                }
                stack.push(num);//此时c[i] == '.'
                num = 0;
            }else{
                a = stack.pop();
                b = stack.pop();
                if(c[i] == '+') stack.push(b + a);
                else if(c[i] == '-') stack.push(b - a);
                else if(c[i] == '*') stack.push(b * a);
                else if(c[i] == '/') stack.push(b / a);
            }
            i++;
        }
        System.out.print(stack.pop());
    }
}

P1739 表达式括号匹配

点击查看代码
//判断括号的顺序、数量匹配即可

import java.util.*;
public class Main{
	 public static void main(String[] args){
	     Scanner sc = new Scanner(System.in);
	     String s = sc.next();
	     char[] c = s.toCharArray();
	     Deque<Character> stack = new ArrayDeque<>();
	     int i = 0;
	     while(c[i] != '@'){
		     if(c[i] == '(') stack.push(c[i++]);
		     else if(c[i] == ')'){
		         if(!stack.isEmpty()){
		             stack.pop();
		             i++;
		         }else{
		             System.out.print("NO");
		             return;
		         }
		     }else i++;
		 }
		 if(stack.isEmpty()) System.out.print("YES");
		 else System.out.print("NO");
	 }
}

直方图最大矩形面积(单调栈)

注意计算面积area的时候必须使用long,不然直接0%,具体图解如下:
image

点击查看代码
import java.util.*;
//单调栈:保证入栈的柱子高度非递减,否则弹栈。
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Deque<Integer> stack = new ArrayDeque<>();//存索引
        int n = sc.nextInt();
        int[] h = new int[n + 2];
        for(int i = 1;i <= n;i++) h[i] = sc.nextInt();//高度
        long max = 0L;
        int height, left;
        long area;
        for(int i = 0;i <= n + 1;i++){
            //h(n+1)用于清空栈,防止最后的柱子算不到,h(0)用于计算中间弹出的几个柱子的较短的部分
            while(!stack.isEmpty() && h[stack.peek()] > h[i]){
                height = h[stack.pop()];            //以弹栈的柱子的高度为基准
                left = stack.peek();                //找到该柱子左边第一个比他矮的,作为左边界
                area = (long)(i - left - 1) * height;     //i作右边界,计算宽度,计算面积
                max = area > max ? (long)area : max;//取面积最大值
            }
            stack.push(i);//空栈、新柱子高于或等于栈顶
        }
        System.out.print(max);
    }
}

二叉树

B3642 二叉树的遍历

输出的内容要使用str.append(i).append(' ');,而不是str.append(i + " ");,因为字符串拼接会产生大量临时String对象,而数据范围n<=1e6导致可能发生爆内存的情况。

只能用 StringBuilder 链式 append

点击查看代码
import java.util.*;

public class Main {
    static class Node {
    	int v, ls, rs;
        Node(int v, int ls, int rs) {
            this.v = v;
            this.ls = ls;
            this.rs = rs;
        }
    }

	public static final int N = (int)1000005;
	public static Node[] t = new Node[N];

	public static void preorder(int i, StringBuilder str) {//先序遍历:根左右
        if (i == 0) return; 
        str.append(t[i].v).append(' ');
        preorder(t[i].ls,str);	
        preorder(t[i].rs,str);	
    }
	
	public static void midorder(int i, StringBuilder str) {//中序遍历:左根右
        if (i == 0) return;
        midorder(t[i].ls,str);	
        str.append(t[i].v).append(' ');
        midorder(t[i].rs,str);
    }
	
	public static void postorder(int i, StringBuilder str) {//后序遍历:左右根
        if (i == 0) return;
        postorder(t[i].ls,str);
        postorder(t[i].rs,str);
        str.append(t[i].v).append(' ');
    }
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int l = 0, r = 0;
        for(int i = 1;i <= n;i++){
            l = sc.nextInt();
            r = sc.nextInt();
            t[i] = new Node(i,l,r);
        }
		int root = 1;
		StringBuilder str = new StringBuilder("");
        preorder(root,str);
        System.out.println(str);
        
        str = new StringBuilder("");
		midorder(root,str);
		System.out.println(str);
		
		str = new StringBuilder("");
		postorder(root,str); 
		System.out.println(str);
	}
}

完全二叉树的权值 183

注意最后一层的节点可能不是满的。

  1. 第i层:\(2^{i-1},2^{i-1} + 1,...,2^{i} - 1,本层总个数2^{i-1}\)
  2. 共k层,节点总个数,\(2^{K} - 1\)
点击查看代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n+1];
        for(int i = 1;i <= n;i++) arr[i] = sc.nextInt();
        int depth = 1;
        int max = Integer.MIN_VALUE, sum = 0;
        int left,right;
        for(int i = 1;;i++){//层数
            left = 1<<(i-1);
            right = Math.min((1<<i) - 1,n);//注意算数运算的优先级高于位运算
            for(int j = left;j <= right;j++){//层节点的序号
                sum += arr[j];
            }
            if(sum > max){
                max = sum;
                depth = i;
            }
            sum = 0;
            if(right == n) break;
        }
        System.out.print(depth);
    }
}

American Heritage 【中序前序→后序】

直接后序输出
public class Main {
    static String mid, pre;
    public static void build(int preStart, int preEnd, int midStart, int midEnd) {
    	//如果节点没有左右孩子,求左右孩子的时候,preStart + 1会导致preStart - preEnd = 1
		if (preStart > preEnd) return;
		char root = pre.charAt(preStart);//子树的根节点
		int index = mid.indexOf(root);//中序,根节点的位置

        int leftLength = index - midStart;//中序,左子树长度

        //左子树的根节点就是该点的左孩子(按照前序划分左右子树)
        build(preStart + 1, preStart + leftLength, midStart, index - 1);
        build(preStart + leftLength + 1, preEnd, index + 1, midEnd);// 右子树
        System.out.print(root);// 后序:左右根
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        mid = sc.next();
        pre = sc.next();
        int n = mid.length();
        build(0, n - 1, 0, n - 1);
    }
}

求先序排列【中序后序→先序】

image

查看代码:直接前序输出
import java.util.*;

public class Main {
    static String mid, post;
    public static void build(int postStart, int postEnd, int midStart, int midEnd) {
    	//如果节点没有左右孩子,求左右孩子的时候,postStart + 1会导致postStart - postEnd = 1
		if (postStart > postEnd) return;
		char root = post.charAt(postEnd);//子树的根节点
		int index = mid.indexOf(root);//中序,根节点的位置

        int leftLength = index - midStart;//中序,左子树长度

        System.out.print(root);// 先序:根左右 
        //左子树的根节点就是该点的左孩子(按照前序划分左右子树)
        build(postStart, postStart + leftLength - 1, midStart, index - 1);
        build(postStart + leftLength, postEnd - 1, index + 1, midEnd);// 右子树
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        mid = sc.next();
        post = sc.next();
        int n = mid.length();
        build(0, n - 1, 0, n - 1);
    }
}

优先队列

餐厅就餐 4348【优先队列】

点击查看代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();//人数
        int m = sc.nextInt();//座位数
        PriorityQueue<Long> q = new PriorityQueue<>();//用餐结束时间
        long a = 0;//到达时间
        long b = 0;//用餐时间
        long start,finish,ans = 0;
        while(n-- > 0){
            a = sc.nextLong();
            b = sc.nextLong();
            start = (q.size() < m) ? a : Math.max(a, q.peek());
            if(q.size() >= m) {
                q.poll();
            }
            finish = (start == a) ? a + b : start + b;
            q.offer(finish);
            ans += start - a + b;
        }
        System.out.print(ans);
    } 
}

image

如果是求最后一个人吃完离开的时间:
image

小蓝的智慧拼图购物【优先队列+贪心】

按照价格从小到大的顺序,优先使用该价格下的优惠折扣最大的优惠券。

价格升序,门槛升序
按照门槛,将所有该价格可以使用的优惠券加入优先队列(大顶堆),使用优惠折扣最大那张。

优先队列里面是:当前这个商品可以使用的、还没被用掉的券
image

点击查看代码
import java.util.*;

public class Main {
  public static void main(String[] args) {
      Scanner sc = new Scanner(System.in);
      int n = sc.nextInt();//拼图个数
      int m = sc.nextInt();//优惠券数量
      long[] p = new long[n];//价格
      long[][] youhui = new long[m][2];//门槛,0是门槛,1是折扣,按照0升序
      for(int i = 0;i < n;i++) p[i] = sc.nextLong();
      for(int i = 0;i < m;i++) youhui[i][0] = sc.nextLong();
      for(int i = 0;i < m;i++) youhui[i][1] = sc.nextLong();
      
      PriorityQueue<Long> q = new PriorityQueue<>((a, b)->{
          return (int)(b - a);
      });//存折扣即可,大顶堆

      Arrays.sort(p);
      Arrays.sort(youhui, (a, b)->{
          return (int)(a[0] - b[0]);
      });

      int j = 0;
      long ans = 0;
      for(int i = 0;i < n;i++){
          while(j < m && youhui[j][0] <= p[i]){//将所有门槛符合的优惠券加入队列
              q.offer(youhui[j][1]);
              j++;
          }
          if(!q.isEmpty()) ans += p[i] - q.poll();
          else ans += p[i];
      }
      System.out.print(ans);
  }
}

栈

NewOJ 排列

点击查看代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n + 1];
        for(int i = 1; i <= n; i++)  a[i] = sc.nextInt();        
        Deque<Integer> st = new ArrayDeque<>();
        long ans = 0L;
        for(int i = 1; i <= n; i++) {
            while(!st.isEmpty() && a[st.peek()] < a[i]) {
                st.pop();
                if(!st.isEmpty()) {//计算栈顶元素与新元素之间的价值,二者之间的内容上一步弹栈出去了,一定小于二者
                    int last = st.peek();
                    ans += (long)(i - last + 1);
                }
            }
            st.push(i);
        }
        ans += (n - 1) * 2L;//任意两个相邻的数据,价值为2
        System.out.println(ans);
    }
}

P1165 日志分析

双栈维护最大值,一个栈a正常存储值,一个栈b的栈顶是当前最大值

  • a弹栈如果弹出当前最大值,即b的栈顶,则b弹栈;
  • a压栈,如果新值比先前的最大值大(b的栈顶),那么该值也压栈进b。

法二:每次遍历栈查询最大值,复杂度很大

点击查看代码
import java.util.*;
import java.io.*;
public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        Deque<Integer> stack = new ArrayDeque<>();
        Deque<Integer> max = new ArrayDeque<>();
        StringBuilder str = new StringBuilder();
        String[] s;
        int a = 0, b = 0;
        while(n-- > 0){
            s = br.readLine().split(" ");
            if(s[0].equals("0")){
                a = Integer.parseInt(s[1]);
                stack.push(a);
                if(max.isEmpty()) max.push(a);
                else if(a > max.peek()) max.push(a);
            }
            else if(s[0].equals("1")) {
            	if(!stack.isEmpty()){
                    b = stack.pop();
                    if(b == max.peek()) max.pop();
                }
            }
            else if(s[0].equals("2")) {
            	if(!stack.isEmpty()) str.append(max.peek() + "\n");
                else str.append("0\n");
            }
        }
        System.out.print(str);
    }
}

P1044 [NOIP 2003 普及组] 栈

法一:递归

欣赏大佬的解题思路:
image

点击查看代码
// h(n) = Σh(i-1)*h(n-i),i = 1, n, 对于第i个数,
//前面所有数的出栈顺序(先出栈) * 后面所有数的出栈顺序(后出栈),是第i个数作为最后一个出栈的数的所有情况
import java.util.*;
public class Main{
    public static int[] arr = new int[20];//记录对应的h(n)
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        // arr[0] = 1;arr[1] = 1;//如果h(n)函数中写了h(0) = 1, h(1) = 1,就不需要写这一行
        System.out.print(h(n));
    }
    public static int h(int n){
        if(arr[n] > 0) return arr[n];//已经记录过这个数(递归结束),直接返回
        if(n < 2) return 1;//h(0) = 1, h(1) = 1
        int sum = 0;
        for(int i = 1;i <= n;i++){
            sum += h(i - 1) * h(n - i);//递归方程
        }
        arr[n] = sum;
        return sum;
    }
}

法二:动态规划(不会)

posted @ 2026-02-07 22:11  idle_life  阅读(39)  评论(0)    收藏  举报