第十四届蓝桥杯 三十天刷题 第十三天

本文分享了四道编程题目,涉及时间模拟处理特殊日期、计算时间重合次数、使用链表处理左移右移操作以及利用双指针求近似最大公约数的问题。文章提供了详细的思路分析和参考代码,强调了模板法和数据结构在解决这类问题中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

📢📢📢哈咯呀各位,又见面啦,让我们愉快的刷题吧~😃😃😃


  1. 🍟🍟🍟特殊日期🍟🍟🍟

📋问题描述

❓思路分享

🍟这是一道典型的时间模拟类的题目,像这种从某天到某天的时间之内,找符合某种条件的天数之类的题目,就用梗佬教的时间模拟器模板,真的太香啦!

🍟时间模拟器就是模拟我们正常的时间走动,一天一天的走下去,包含了闰年的判断,因为这样的天数的话数字不会很大,所以大可不必担心会超时或者等很长时间才会跑出答案来,真的是谁用谁说好

📗参考代码

/**
 * @ClassName 特殊时间
 * @Author @浅夜
 * @Date 2023/3/16 19:11
 * @Version 1.0
 */

public class Main {
    static int[] w = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    static int y = 1900, m = 1, d = 1;


    public static void main(String[] args) {
        int ans = 0;
        while (y != 9999 || m != 12 || d != 31) {
            if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) w[2] = 29;
            else w[2] = 28;
            d++;
            if (d > w[m]) {
                m++;
                d = 1;
            }
            if (m > 12) {
                m = 1;
                y++;
            }

            if (check(y, m, d)) ans++;
        }
        System.out.println(ans);

    }

    static boolean check(int y, int m, int d) {
        int p = 0, q = 0;
        //因为y,m,d是全局变量,防止接下来的操作改变他们的值,所以这里需要备份一下
        int year = y;
        int month = m;
        int day = d;
        while (year > 0) {
            p += year % 10;
            year /= 10;
        }
        while (month > 0) {
            q += month % 10;
            month /= 10;
        }
        while (day > 0) {
            q += day % 10;
            day /= 10;
        }
        return p == q;
    }
}


  1. 🍥🍥🍥重合次数🍥🍥🍥

📋问题描述

❓思路分享

🍥跟第一道题一样,不过变成了模拟更加精细的时间了,原理都是一样的。

我看群里讨论说模拟的话会每个小时多出一次来,我后面看了看,貌似是在分针和秒针走到60 之后,应该都是从1开始的,像模拟成每个小时多出一次的情况是到60之后从0开始的,那样的的话就相当于是把00位置多加了一次(应该是这样吧,我从0开始的话模拟答案是对的,不用再减去小时数)。

📗参考代码

/**
 * @ClassName 重合次数
 * @Author @浅夜
 * @Date 2023/3/16 20:02
 * @Version 1.0
 */

public class Main {
    public static void main(String[] args) {
        int h = 6,m = 13,s = 22;
        int ans = 0;
        while(h != 14 || m != 36 || s != 20){
            s++;
            if(s==60){
                m++;
                s = 1;
            }
            if(m == 60){
                m = 1;
                h++;
            }
            if(m == s) ans++;
        }
        System.out.println(ans);//494
    }
}


  1. 🍔🍔🍔左移右移🍔🍔🍔

📋问题描述

❓思路分享(来自梗佬的题解

🍔我们要做的有两件事:第一,查找某个点所在位置;第二,频繁的插入和删除;

🍔频繁的插入删除我们就使用链表来实现,左右两边都要进行插入的话就使用双链表,它可以在O(1)时间进行插入和删除,但是n的范围是2e5,如果直接通过遍历来查找元素的位置的话,显然是很慢的,那我们就通过哈希表来进行查询操作,key为元素值,value为链表节点对象。

📗参考代码

import org.w3c.dom.Node;

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    static Map<Integer, Node> map = new HashMap<>();
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        //双向链表的头结点和尾结点
        Node head = new Node(-1, null, null);
        Node last = new Node(-1, null, null);
        Node pre = head;
        //构建双链表
        for (int i = 1; i <= n; i++) {
            pre.next = new Node(i, pre, null);
            pre = pre.next;
            map.put(i, pre);
        }
        last.pre = pre;
        pre.next = last;
        for (int i = 0; i < m; i++) {
            char c = sc.next().charAt(0);
            int x = sc.nextInt();
            Node node = map.get(x);
            node.pre.next = node.next;
            node.next.pre = node.pre;
            if (c == 'L') {
                node.next = head.next;
                head.next.pre = node;
                head.next = node;
                node.pre = head;
            } else {
                node.pre = last.pre;
                last.pre.next = node;
                node.next = last;
                last.pre = node;
            }
        }
        pre = head.next;
        while (pre != last) {
            out.print(pre.v + " ");
            pre = pre.next;
        }
        out.flush();
    }

    //双向链表的有参构造方法
    static class Node {
        int v;
        Node pre;
        Node next;

        public Node(int v, Node pre, Node next) {
            this.v = v;
            this.pre = pre;
            this.next = next;
        }
    }
}


  1. 🌀🌀🌀近似gcd🌀🌀🌀

📋问题描述

❓思路分享

🌀前置知识:

  • 如果一个数组中只有一个数不满足它的约数为g,那么我们只需要将它变成g,就能满足该数组的最大公约数为g了。

  • 一个数组如果只有一个不满足g为数组最大公约数的元素,那么该数组以及该数组长度不小于2的子数组都是满足题意的数组。

🌀有了这两点的理解,我们就可以用双指针来实现了,r指针来遍历数组,l指针来找符合条件数组的起点,将原数组中将g的倍数全部赋1,否则赋值为0,并将赋值后的数组维护成一个前缀和数组,这样我们就可以通过比较前缀和数组某一段的差与其下标差,就可以找出满足只有一个不满足最大公约数为g的最长数组了。

📗参考代码

import java.io.*;

/**
 * @ClassName 近似gcd
 * @Author @浅夜
 * @Date 2023/3/16 21:20
 * @Version 1.0
 */

public class 近似gcd {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    static int N = 200010;
    static int n, g;
    static int[] a = new int[N];

    public static void main(String[] args) throws IOException {
        String[] s = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        g = Integer.parseInt(s[1]);
        s = br.readLine().split(" ");
        for (int i = 1; i <= n; i++) {
            a[i] = Integer.parseInt(s[i - 1]) % g == 0 ? 1 : 0;
            a[i] += a[i - 1];
        }
        long ans = 0L;
        int l = 0;
        for (int r = 2; r <= n; r++) {
            while (l + 1 < r && a[r] - a[l] + 1 < r - l) l++;
            ans += r - l - 1;
        }
        out.println(ans);
        out.flush();
        br.close();
    }
}


📢📢📢好啦,今天的分享就是这些了,今天还补了一手bfs和连通块之类的问题,感觉像这种模板性的东西用起来真的太香啦,有时间写几篇题解跟大家分享哈~

动动小手点点赞就有热乎题解来啦😋

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值