【蓝桥杯】练习题目合集(自用)-1
题单
- 数组:洛谷题单 - 数组 😎
![image]()
- 队列 🎉
- 优先队列😭
- 题库练习(包含省赛部分)
- 蓝桥题库-标签-优先队列(标签并不准确)
- 合并果子 741【优先队列、小顶堆】
- 餐厅就餐 4348【优先队列、小顶堆】【经典】
- Windows的消息队列【优先队列,自定义排序】
- 小蓝的智慧拼图购物【优先队列,贪心,大顶堆】
- 删字母 6272【双端队列、优先队列思想】
- 小桥的冒险【贪心,模拟,优先队列思想】
- 省赛:
- Fibonacci 集合 2362 【简单,排序,去重】✔️
- 作物杂交 506 【dp,dfs】❌
- 整数删除 3515 ❌
- 最大开支 3541 ❌
- 原料采购 20511 ❌
- 小蓝的旅行计划 3534 ❌
- 题库练习(包含省赛部分)
- 栈 🙀
- 排列(NewOJ 这绝对是目前为止我用过最难用的OJ平台,看不了提交源代码、不保存写过的代码,刚提交完就没了)
- 小鱼的数字游戏
- 后缀表达式
- P1044 [NOIP 2003 普及组] 栈
- 【模板】栈
- 表达式括号匹配
- P1165 日志分析
- 妮妮的神秘宝箱 3743 括号匹配问题
- 直方图的最大建筑面积 4516 单调栈典型问题
- 小蓝的括号串 2490
- 小邋遢的衣橱 1229
- 二叉树 😎 (大多和搜索(BFS、DFS)、路径计算、动态规划有关,下面是二叉树概念题)
- 完全二叉树的权值 183 【经典】构造完全二叉树,实际上一个数组就够了,不需要Node节点
- FBI树 【经典】 递归构造二叉树,后序遍历
- P1087 [NOIP 2004 普及组] FBI 树 【经典】 递归构造二叉树,后序遍历
- B3642 二叉树的遍历 【经典】三种遍历
- American Heritage 【经典】根据前序遍历、中序遍历,求后序遍历
- 求先序排列 【经典】中序与后序 → 前序
- P1305 新二叉树 二叉树构造,前序遍历
同余方程组
点击查看代码
//法一
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的所有分解方式。
圆弧的数学问题【×】

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));
}
}
这个哥们推理了为啥一次【右、弧】是最短的。

客流量上限 20550【×】

TODO:没看明白答案
大佬解析:

幻方矩阵
点击查看代码
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();
}
}
}
模拟
蛇形矩阵
点击查看代码
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();
}
}
}
杨辉三角
点击查看代码
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();
}
}
}
数组越界问题
点击查看代码
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);
}
}
字符串压缩技术
点击查看代码
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;
}
}

完美数对【枚举】
点击查看代码
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%,具体图解如下:

点击查看代码
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
注意最后一层的节点可能不是满的。
- 第i层:\(2^{i-1},2^{i-1} + 1,...,2^{i} - 1,本层总个数2^{i-1}\)
- 共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);
}
}
求先序排列【中序后序→先序】

查看代码:直接前序输出
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);
}
}

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

小蓝的智慧拼图购物【优先队列+贪心】
按照价格从小到大的顺序,优先使用该价格下的优惠折扣最大的优惠券。
价格升序,门槛升序
按照门槛,将所有该价格可以使用的优惠券加入优先队列(大顶堆),使用优惠折扣最大那张。
优先队列里面是:当前这个商品可以使用的、还没被用掉的券

点击查看代码
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 普及组] 栈
法一:递归
欣赏大佬的解题思路:

点击查看代码
// 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;
}
}
法二:动态规划(不会)


浙公网安备 33010602011771号