【小赛1】蓝桥杯双周赛第5场(小白)思路回顾

news2025/7/12 16:45:20

我的成绩:小白(5/6)

完稿时间:2024-2-13

比赛地址:https://www.lanqiao.cn/oj-contest/newbie-5/

相关资料:

1、出题人题解:“蓝桥杯双周赛·第5次强者挑战赛/小白入门赛”出题人题解 - 知乎 (zhihu.com)

2、矩阵快速幂:算法学习笔记(4):快速幂 - 知乎 (zhihu.com)

  • 讲得挺好的,从快速幂到矩阵快速幂,以及在求解递推式中的应用。

3、矩阵乘法结合律证明:如何把矩阵乘法结合律的证明写得简单易懂(针对初学者) - 知乎 (zhihu.com)

  • 我突然疑惑矩阵乘法为什么会满足结合律,找了篇文章,还没来得及看

文章目录

  • 一、我思路回顾
    • 1、十二生肖
    • 2、欢迎参加福建省大学生程序设计竞赛
    • 3、匹配二元组的数量
    • 4、元素交换
    • 5、下棋的贝贝
  • 二、补题
    • 6、方程
  • 三、小结
    • *脱节:从实践出发,又要从基础出发
    • 回顾此回顾

一、我思路回顾

1、十二生肖

思路:

此题令我有点意外,显然2024是龙年,在12生肖中排第5个,print即可。

代码:

print(5)

2、欢迎参加福建省大学生程序设计竞赛

思路:

题中说将相同题数,相同罚时的队伍归为一类,那么如果每行输入作为一个元素,问题就变成了:有多少个不同的元素。而刚好集合数据结构就具有元素不重复的特点,将所有输入数据加入集合,输出集合中元素数量即可。

在python中,输入是字符串,将它作为字典的键就可实现去重。

代码:

if __name__ == '__main__':
    n = int(input())
    d = {}
    for i in range(n):
        x = input()
        if x not in d:
            d[x] = 1
    print(len(d))

3、匹配二元组的数量

思路:

这题想了一会儿,看到比值就想一项,但移完之后呢?

a i j = a j i \frac{a_i}{j}=\frac{a_j}{i} jai=iaj,变形一下, i a i = j a j ia_i=ja_j iai=jaj,于是可以将数组A的每一元素乘以它的下标,得新数组B,后统计B中重复元素数量。(注这里下标从1开始)

出现2次的算1一个匹配二元组,出现3次的算3个······出现x次的算组合数 C x 2 C^2_x Cx2,即 x ! 2 \frac{x!}{2} 2x!

代码:

def f(x):
    '''x的阶乘'''
    r = 1
    for i in range(x):
        t = i + 1
        r *= t 
    return r

if __name__ == '__main__':
    n = int(input())
    nums = [int(x) for x in input().split(' ')]
    d = {}
    for i, num in enumerate(nums):
        nums[i] = (i + 1) * num 
    for num in nums:
        if num not in d:
            d[num] = 0
        d[num] += 1

    result = 0
    for key in d:
        result += f(d[key]) // 2
    print(result)

4、元素交换

思路:

这题像脑筋急转弯,初看非常的手足无措。

数组中有N个0和N个1,“不存在连续的0或1”,那合规数组仅两种:1)010101...,2)101010...,于是逐项对比输入与合规数组,得不同的项的数量c,而每次交换可以把两个不同项变为相同,所以交换次数为n/2 。

那为什么,每次交换可以减少两个不同?

因为1对上0的数量,必然和0对上1的数量一样。不妨令N为5,假设合规数组中,有3个1没匹配上。那么必然有2个1匹配上了,那么输入中还剩3个1,让合规数组中的0也有3个匹配不上。

合规:0 1 0 1 0 1 0 1 0 1
输入:  0   0   0   1   1

在比赛中,我经常就只能先将输入胡乱摆弄一阵,然后去猜规律,有时猜得对,有时猜得半对,有时猜得不对。在下一题,下棋的贝贝中,就是先草率地猜错了,然后又重新猜。

代码:

def jdz(x):
    '''绝对值'''
    return x if x >= 0 else -x

if __name__ == '__main__':
    n = int(input())
    nums = [int(x) for x in input().split(' ')]

    # 合规数组
    h1 = [0, 1] * n 
    h2 = [1, 0] * n

    # 对比差距
    c1 = sum([jdz(h1[i] - nums[i]) for i in range(len(nums))])
    c2 = sum([jdz(h2[i] - nums[i]) for i in range(len(nums))])
    c = min(c1, c2)

    r = c // 2  # 每次交换可以减少两个不同
    print(r)

5、下棋的贝贝

思路:

题意还比较清晰,在整数格子上放棋子,横竖挨着的棋子算相邻,相邻的棋子有一条边,如果边的总数为e,输出 2 ∗ e 2*e 2e

于是我开始在草稿纸上施法,期待老天爷降下神谕。很快我就觉得,这是一个类似等差的数列,之后隔两项的差都是3。然而提交之后的error告诉我,还是高兴得太早了。

在这里插入图片描述

于是我又猜了第二版。有的棋子放下时不增加边(1号)或只会增加一条边,如下图中带圈圈的;有的棋子放下时增加两条边,如下图中不带圈圈的。然后统计带圈圈类型的棋子数量。

设总棋子数为m,平方根向下取整为n,于是带圈圈的棋子数single_edge分两类统计:

  1. 一个是内侧正方形中的(如图中蓝框),数量为2n-1
  2. 外正方形的,会有两个临界值,当m的值超过它们时,带圈圈的棋子数加1。

如果每个棋子会产生两条边,那么总边数为 2 m 2m 2m。然后减去只产生一条边的棋子数量(因为一号棋子不产生边,可以抵两个只产生一条边的棋子),就可以得到边的总数。

在这里插入图片描述

为什么以上方法就是放置棋子的最佳策略(产生最多的边)?

大家可以思考一下。

代码:

import math

def method2(m):
    '''边的数量'''
    n = math.sqrt(m)
    n = math.floor(n)
    single_edge = n * 2
    if m >= n**2 + 1:
        single_edge += 1
    if m >= n**2 + 1 + n:
        single_edge += 1 
    r = 2 * m - single_edge
    return r

if __name__ == '__main__':
    m = int(input())
    r = method2(m)
    print(r * 2)

二、补题

6、方程

这题当时完全没有思路,希望我下次会有进步。如果还没有,就多下几次!

思路:

有两个步骤。第一步是得到递推式,但n数据范围是 [ 1 , 1 0 9 ] [1,10^9] [1,109],逐步递推时间复杂度 O ( n ) O(n) O(n)太高。于是第二步用到矩阵快速幂,将复杂度降到 O ( l o g n ) O(logn) O(logn)

1、得到递推式

题为 x + 1 x = k x+\frac{1}{x}=k x+x1=k,求 x n + 1 x n x^n+\frac{1}{x^n} xn+xn1的值。令 f ( n ) = x n + 1 x n f(n)=x^n+\frac{1}{x^n} f(n)=xn+xn1,则: k f ( n ) = ( x + 1 x ) ( x n + 1 x n ) = f ( n + 1 ) + f ( n − 1 ) kf(n)=(x+\frac{1}{x})(x^n+\frac{1}{x^n})=f(n+1)+f(n-1) kf(n)=(x+x1)(xn+xn1)=f(n+1)+f(n1)

即: f ( n + 1 ) = k f ( n ) − f ( n − 1 ) f(n+1)=kf(n)-f(n-1) f(n+1)=kf(n)f(n1)

又易得: f ( 0 ) = 2 f(0)=2 f(0)=2 f ( 1 ) = k f(1)=k f(1)=k

2、矩阵快速幂

这部分参考了文首的资料1和资料2,大家也可以看一下。

a、为什么要有快速幂算法?

在求一个数的n次幂的过程中,比如 1 0 8 = 10 ∗ 10 ∗ 10 ∗ 10 ∗ 10 ∗ 10 ∗ 10 ∗ 10 10^8=10*10*10*10*10*10*10*10 108=1010101010101010,需要8次乘法运算。但如果这样算: 1 0 2 = 10 ∗ 10 , 1 0 4 = 1 0 2 ∗ 1 0 2 , 1 0 8 = 1 0 4 ∗ 1 0 4 10^2=10*10,10^4=10^2*10^2,10^8=10^4*10^4 102=1010104=102102108=104104,只需要3次乘法,这其实是二分的思路。

也就是说,可以以 O ( l o g n ) O(logn) O(logn)的时间复杂度计算数x的n次幂 x n x^n xn

b、矩阵乘法如何计算递推式?

就以本题为例,我们发现 [ k − 1 1 0 ] [ f n − 1 f n − 2 ] = [ f n f n − 1 ] \begin{bmatrix}k & -1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix}f_{n-1}\\f_{n-2} \end{bmatrix} = \begin{bmatrix}f_{n}\\f_{n-1} \end{bmatrix} [k110][fn1fn2]=[fnfn1] ,于是我们每一次矩阵乘法,就是一步递推。

但这有什么用呢,好像莫名奇妙凑出一个矩阵的形式,把简单的问题复杂化。

c、快速幂加上矩阵乘法:快速计算递推式。

A = [ k − 1 1 0 ] A=\begin{bmatrix}k & -1 \\ 1 & 0 \end{bmatrix} A=[k110] ,则: [ f n f n − 1 ] = A [ f n − 1 f n − 2 ] = A 2 [ f n − 2 f n − 3 ] = . . . = A n − 1 [ f 1 f 0 ] \begin{bmatrix}f_{n}\\f_{n-1} \end{bmatrix} = A \begin{bmatrix}f_{n-1}\\f_{n-2} \end{bmatrix} = A^2 \begin{bmatrix}f_{n-2}\\f_{n-3} \end{bmatrix} = ... = A^{n-1} \begin{bmatrix}f_{1}\\f_{0} \end{bmatrix} [fnfn1]=A[fn1fn2]=A2[fn2fn3]=...=An1[f1f0]

看见 A A A头上的幂次了吗?将递推的时间复杂度从 O ( n ) O(n) O(n)降到 O ( l o g n ) O(logn) O(logn),我想你已经知道该怎么做了。

代码:

class Matrix:
    '''封装矩阵乘法'''
    MOD_NUM = 10**9 + 7

    def __init__(self, value) -> None:
        self.v: list = value 
    
    def mul(self, obj):
        # 两个矩阵维度分别是(a,b), (b,c)
        obj: Matrix = obj
        a, b, c = len(self.v), len(self.v[0]), len(obj.v[0])
        
        matrix = [[0] * c for i in range(a)]  # 乘积维度:(a,c)
        r = Matrix(matrix)
        for i in range(a):
            for j in range(c):
                for k in range(b):
                    r.v[i][j] = (r.v[i][j] + self.v[i][k] * obj.v[k][j]) % self.MOD_NUM
        return r


def mi(A: Matrix, n: int) -> Matrix:
    '''求矩阵A的n次幂'''
    if n == 1:
        return A
    if n % 2 == 1:
        return mi(A, n-1).mul(A)
    else:
        t = mi(A, n // 2)
        return t.mul(t)

def method(n, k):
    '''求解一个测试用例'''
    if n == 1:
        return k 
    elif n > 1:
        A = Matrix([[k, -1], [1, 0]])
        F = Matrix([[k], [2]])  # f(0)=2, f(1)=k
        R = mi(A, n-1).mul(F)
        return R.v[0][0]

if __name__ == '__main__':
    m = int(input())
    for _ in range(m):
        n, k = map(int, input().split(' '))  # 以前我总用列表推导式
        print(method(n, k))


这次比赛强者级还有3个题,但比赛就没看,相关内容也没咋学,又考虑到时间问题,就不打算补了。

三、小结

本次比赛有小白和强者两个级别,感觉自己还比较菜,于是报了小白。后来发现小白的后3题正是强者级的头三题,这么看来,我在强者级只能写两个题?但问题不大,我对未来仍然抱有一种迷之信心。

*脱节:从实践出发,又要从基础出发

脱节问题在我们的生活中尤其严重。常有人说大学教育与社会需求脱节。然而细看我自己,又何尝不是处处脱节?就如学英语数十年,却不能说英语,学习和运用是脱节的。读英文时脑海里止步于模糊的“英式汉语”,想将心中的地道汉语用英语说出来,自然是困难的,因为缺少了一个从输入英语到地道汉语的过程。盲目期待所谓“英语思维”,于是学习方法本身便是脱节的。汉语是我们的母语,想将它一下子甩掉不太现实。

早在学校的数据结构与算法课程,弊端就已经显现。算法本身被孤立地灌输给我,要我如何能够面对问题分析问题用算法解决问题?大多的算法都只是跟着实现一遍,也大概就算是学过了。诚然,师傅领进门,修行靠个人,学习本就要靠自己的努力。可我就是缺少指导呀。(吐槽)

回看算法的学习,也应该多参加小比赛,多自己写,才能学会自己写。实践中有其独特而珍贵的经验,而且能为学习方向的调整提供指导。

然而,也常听见一个建议:在做的过程中学。但我曾理解得有些片面,于是钟爱教程而疏于理论,止于模仿而失了变通;于是遇到难题抓脑袋,有一段时间,沉陷在反复的焦虑之中。后来有一次zxl对我说,解决不了,就要想想是不是缺了基础知识,又让我一下子觉得:早该这样。

再看算法学习,总专注于比赛、刷题,而不重视系统性的理论学习,同样不合适。望自警醒。

拼命追着跑还是被匆匆拖着跑,都不太好,得一起跑。

回顾此回顾

要常回顾,以免在歧途上发足狂奔。但我目前有一个大问题,就是我太慢了,相当于在路上花费了太多的时间东张西望。此次比赛回顾,写到这句话,我已经花了8小时。比赛本身也才2小时!

这种习惯对于“常回顾”的目标,必然是极大的负担。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1447197.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Java 简易速速上手小册》第9章:Java 开发工具和框架 (2024 最新版)

文章目录 9.1 Maven 和 Gradle - 构建与依赖管理的神兵利器9.1.1 基础知识9.1.2 重点案例:使用 Maven 构建 Spring Boot 应用9.1.3 拓展案例 1:使用 Gradle 构建多模块项目9.1.4 拓展案例 2:利用 Gradle Wrapper 确保构建的一致性 9.2 Spring…

【JavaEE Spring】Spring 原理

Spring 原理 1. Bean的作⽤域1.1 概念1.2 Bean的作⽤域 2. Bean的⽣命周期 1. Bean的作⽤域 1.1 概念 在Spring IoC&DI阶段, 我们学习了Spring是如何帮助我们管理对象的. 通过 Controller , Service , Repository , Component , Configuration ,Bean 来声明Bean对象。通…

数学建模:K-means聚类手肘法确定k值(含python实现)

原理 当K-means聚类的k值不被指定时,可以通过手肘法来估计聚类数量。   在聚类的过程中,随着聚类数的增大,样本划分会变得更加精细,每个类别的聚合程度更高,那么误差平方和(SSE)会逐渐变小&am…

备战蓝桥杯---图论基础理论

图的存储&#xff1a; 1.邻接矩阵&#xff1a; 我们用map[i][j]表示i--->j的边权 2.用vector数组&#xff08;在搜索专题的游戏一题中应用过&#xff09; 3.用邻接表&#xff1a; 下面是用链表实现的基本功能的代码&#xff1a; #include<bits/stdc.h> using nam…

那些 C语言指针 你不知道的小秘密 (完结篇)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人能…

蓝桥杯嵌入式第11届真题(完成) STM32G431

蓝桥杯嵌入式第11届真题(完成) STM32G431 题目 代码 程序和之前的大同小异&#xff0c;不过多解释 main.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief :…

第4讲 小程序首页实现

首页 create.vue <template><view class"vote_type"><view class"vote_tip_wrap"><text class"type_tip">请选择投票类型</text><!-- <text class"share">&#xe739;分享给朋友</text&g…

免费分享一套PyQt6学生信息管理系统 Python管理系统 Python源码,挺漂亮的

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的PyQt6学生信息管理系统 Python管理系统 Python源码&#xff0c;分享下哈。 项目视频演示 【免费】PyQt5 学生信息管理系统 Python管理系统 Python源码 Python毕业设计_哔哩哔哩_bilibili【免费】PyQt5 学生…

康熙字典的部首里为啥没有王字旁

很多汉字的偏旁部首&#xff0c;是“王”&#xff0c;但在康熙字典的部首列表里&#xff0c;却没有它。而新华字典是有的。 这不科学啊&#xff0c;于是我还通过Unicode编码查了下康熙部首的编码部分&#xff0c;确认了一下&#xff0c;发面里面确实没有。 康熙部首&#xff08…

顺序表、链表(ArrayList、LinkedList)

目录 前言&#xff1a; 顺序表&#xff08;ArrayList&#xff09;&#xff1a; 顺序表的原理&#xff1a; ArrayList源码&#xff1a; 的含义&#xff1a;​编辑 ArrayList的相关方法&#xff1a;​编辑 向上转型List&#xff1a; 练习题&#xff08;杨辉三角&#x…

单页404源码

<!doctype html> <html> <head> <meta charset"utf-8"> <title>简约 404错误页</title><link rel"shortcut icon" href"./favicon.png"><style> import url("https://fonts.googleapis.co…

Java中抽象类和接口的区别

抽象类和接口都是 Java 中多态的常见使用方式. 都需要重点掌握. 同时又要认清两者的区别(重要!!! 常见面试题)。 核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写而重写抽象方法), 而接口中不能包含普通方法&#xff08;接口…

生成式人工智能(AIGC)之最全详解图解

生成式人工智能&#xff08;AIGC&#xff09;之最全详解图解 1. AIGC的发展历程1.1 AIGC演化重要时间节点AIGC发展历程图OpenAI大语言模型发展进程 1.2技术推进路线 2.AIGC技术场景2.1 技术场景 3.1AIGC相关应用4.AIGC未来发展前景 1. AIGC的发展历程 AIGC&#xff08;AI-Gene…

ClickHouse--04--数据库引擎、Log 系列表引擎、 Special 系列表引擎

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.数据库引擎1.1 Ordinary 默认数据库引擎1.2 MySQL 数据库引擎MySQL 引擎语法字段类型的映射 2.ClickHouse 表引擎3.Log 系列表引擎几种 Log 表引擎的共性是&#…

任务调度

1.学习目标 1.1 定时任务概述 1.2 jdk实现任务调度 1.3 SpringTask实现任务调度 1.4 Spring-Task 分析 1.5 Cron表达式 https://cron.qqe2.com/ 2. Quartz 基本应用 2.1 Quartz 基本介绍 2.2 Quartz API介绍 2.3 入门案例 <dependency> <groupId>org.springframe…

《Java 简易速速上手小册》第7章:Java 网络编程(2024 最新版)

文章目录 7.1 网络基础和 Java 中的网络 - 揭开神秘的面纱7.1.1 基础知识7.1.2 重点案例&#xff1a;实现一个简单的聊天程序7.1.3 拓展案例 1&#xff1a;使用 UDP 进行消息广播7.1.4 拓展案例 2&#xff1a;建立一个简单的 Web 服务器 7.2 创建客户端和服务器 - 构建沟通的桥…

Microsoft Word 清除格式

Microsoft Word 清除格式 References 选择文本&#xff0c;用快捷键 Ctrl Shift N&#xff0c;可以快速清除格式。 选择文本&#xff0c;清除格式。 References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

Java图形化界面编程—— ImageIO 笔记

2.8.4 ImageIO的使用 在实际生活中&#xff0c;很多软件都支持打开本地磁盘已经存在的图片&#xff0c;然后进行编辑&#xff0c;编辑完毕后&#xff0c;再重新保存到本地磁盘。如果使用AWT要完成这样的功能&#xff0c;那么需要使用到ImageIO这个类&#xff0c;可以操作本地磁…

【数据结构】二叉树先序、中序、后序及层次四种遍历(C语言版)

数据结构——二叉树先序、中序、后序三种遍历 一、图示展示&#xff1a; &#xff08;1&#xff09;先序遍历&#xff08;2&#xff09;中序遍历&#xff08;3&#xff09;后序遍历&#xff08;4&#xff09;层次遍历&#xff08;5&#xff09;口诀 二、代码展示&#xff1a; 一…

使用JNDI API

使用JNDI API Java EE应用程序使用JNDI API作为通用的名称查找服务来查找组件、外部资源和组件环境属性。JNDI API公开底层命名协议和实现的详细信息。 1. JNDI API的架构 JNDI架构由以下组件组成: JNDI API:它可让Java应用程序访问各种命名服务和目录服务。JNDI服务提供商接…