Misaka-xxw的博客

昨日种种,皆成今我

数学符号

基本数学符号

符号 LaTeX 命令 符号 LaTeX 命令 符号 LaTeX 命令
± \pm \mp × \times
÷ \div \sqrt \sqrt[3]
! ! ? ? \sum
\prod \int \iint
\iiint \oint \bigcup
\bigcap \bigvee \bigwedge

希腊字母

小写字母符号 小写字母LaTeX命令 大写字母符号 大写字母LaTeX命令
α \alpha Α \Alpha
β \beta Β \Beta
γ \gamma Γ \Gamma
δ \delta Δ \Delta
ε \epsilon Ε \Epsilon
ζ \zeta Ζ \Zeta
η \eta Η \Eta
θ \theta Θ \Theta
ι \iota Ι \Iota
κ \kappa Κ \Kappa
λ \lambda Λ \Lambda
μ \mu Μ \Mu
ν \nu Ν \Nu
ξ \xi Ξ \Xi
π \pi Π \Pi
ρ \rho Ρ \Rho
σ \sigma Σ \Sigma
τ \tau Τ \Tau
υ \upsilon Υ \Upsilon
φ \phi Φ \Phi
χ \chi Χ \Chi
ψ \psi Ψ \Psi
ω \omega Ω \Omega

微积分符号

符号 LaTeX 命令 符号 LaTeX 命令 符号 LaTeX 命令
\int \iint \iiint
\oint \partial \frac{d}{dx}
\nabla lim \lim \infty

集合论符号

符号 LaTeX 命令 符号 LaTeX 命令 符号 LaTeX 命令
\in \notin \subset
\supset \subseteq \supseteq
\cap \cup \emptyset
Δ \Delta Φ \Phi Γ \Gamma

逻辑符号

符号 LaTeX 命令 符号 LaTeX 命令 符号 LaTeX 命令
\land \lor ¬ \neg
\rightarrow \leftarrow \Rightarrow
\Leftarrow \forall \exists

线性代数符号

符号 LaTeX 命令 符号 LaTeX 命令 符号 LaTeX 命令
\oplus \otimes \odot
\perp \angle \cdot
\parallel \land \lor
\rightharpoonup \leftharpoonup
A^T A^{-1} \operatorname{rank}

矩阵和行列式

符号 LaTeX 命令 符号 LaTeX 命令 符号 LaTeX 命令
[ ] \begin{pmatrix}...\end{pmatrix} [ ] \begin{bmatrix}...\end{bmatrix} [ ] \begin{Bmatrix}...\end{Bmatrix}
[ ] \begin{vmatrix}...\end{vmatrix} [ ] \begin{Vmatrix}...\end{Vmatrix}
[ ] \begin{matrix}...\end{matrix}

其他常见符号

符号 LaTeX 命令 符号 LaTeX 命令 符号 LaTeX 命令
\approx \equiv \leq
\geq \neq ± \pm
\mp \partial \nabla

上下标和分数

符号 LaTeX 命令 符号 LaTeX 命令
x^2 y_i
z^{i+1}_j \frac{a}{b}

箭头

符号 LaTeX 命令 符号 LaTeX 命令 符号 LaTeX 命令
\leftarrow \rightarrow \leftrightarrow
\Leftarrow \Rightarrow \Leftrightarrow
\longleftarrow \longrightarrow \longleftrightarrow
\Longleftarrow \Longrightarrow \Longleftrightarrow
\uparrow \downarrow \updownarrow
\Uparrow \Downarrow \Updownarrow
\mapsto \hookrightarrow \hookleftarrow
\rightharpoonup \leftharpoondown \rightleftharpoons
\nearrow \swarrow \nwarrow
\searrow

关系代数

中文 符号 LATEX命令
投影 Π \Pi
选择 σ \sigma
重命名 ρ \rho
聚合函数 G \mathcal{G}
\cup
\cap
自然连接 \bowtie\Join
左外连接 (直接复制吧)
右外连接 (同上)
全外连接 (同上)
笛卡尔乘积 × \times
÷ \div
赋值 \leftarrow
条件并列 \land\vee
¬ \neg
存在 \exists
对所有 \forall

参考

Not just for exam.

参考:林子雨老师的《数据库系统原理》,以及《软件设计师教程》

写在前面:刻在DNA里的学生选课数据库

本章的所有实例都以学生选课数据库为基础,该数据库包括5个表:

  1. 学生表Student(Sno, Sname, Ssex, Sage, Sdept);
  2. 课程表Course(Cno, Cname, Cpno, Ccredit);
  3. 学生选课表SC(Sno, Cno, Grade);
  4. 教师表Teacher(Tno, Tname, Tsex, Tage);
  5. 授课表TC(Tno, Cno)。

每一个表的第一列都是主码。

Student

Sno Sname Sex Sage Sdept
2024001 林书凡 18 MA
2024002 李欣然 19 IS
2024003 王武义 20 CS
2024004 苏文甜 19 CS

Course

Cno Cname Cpno Ccredit
1 大数据 3 2
2 操作系统 5 4
3 数据库 5 4
4 编译原理 NULL 4
5 编程语言 NULL 2
6 数据挖掘 3 2

SC

Sno Cno Grade
2024001 1 97
2024001 2 78
2024001 3 86
2024002 2 85
2024002 3 77

Teacher

Tno Tname Tsex Tage
97001 林形文 45
97002 司马鹰松 33
97003 王明天 38
97004 马晓燕 36
97005 张勇 51

TC

Tno Cno
97001 1
97001 3
97002 2
97003 4
97004 5
97004 6
97005 6

数据库概述

关系数据库

关系运算

逻辑表达式

运算符 含义
比较运算符 > 大于
>= 大于等于
< 小于
<= 小于等于
= 等于
<> 不等于
逻辑运算符 ¬

八种关系运算

  1. 并(Union)

    • 符号:
    • 作用:合并两个关系中的元组,去除重复的元组。
    • 表示:,表示关系R和关系S的并集。
  2. 交(Intersection)

    • 符号:
    • 作用:找出两个关系中共有的元组。
    • 表示:,表示关系R和关系S的交集。
  3. 差(Difference)

    • 符号:
    • 作用:从第一个关系中移除与第二个关系中相同的元组。
    • 表示:,表示关系R中不在关系S中的元组。
  4. 选择(Selection)

    • 符号:
    • 作用:从关系中选择满足特定条件的元组()。
    • 表示:,表示从关系R中选择满足条件的元组。
  5. 投影(Projection)

    • 符号:
    • 作用:从关系中选择特定的属性
    • 表示:,表示从关系R中选择指定的属性列。
  6. 连接(Join)

    • 符号:
    • 作用:将两个关系中满足特定条件的元组合并成一个新的关系。
    • 表示:,表示关系R和关系S的自然连接。
      • 条件连接θ-连接):,其中是连接条件,可以是等比较运算符,表示基于这些条件的连接。
      • 外连接(Outer Join):当两个关系中没有完全匹配的元组时,外连接可以返回其中一个关系的所有元组,以及另一个关系中匹配的元组。如果另一个关系中没有匹配的元组,则结果中对应的字段为NULL
        • 左外连接(Left Outer Join):返回左关系(R)的所有元组,即使在右关系(S)中没有匹配的元组。如果右关系中没有匹配的元组,则结果中右关系的部分为NULL
          • 表示:Double subscripts: use braces to clarifyR \underset{A \theta B}{\Join}_{\text{L}} S 或者
        • 右外连接(Right Outer Join):返回右关系(S)的所有元组,即使在左关系(R)中没有匹配的元组。如果左关系中没有匹配的元组,则结果中左关系的部分为NULL
          • 表示:Double subscripts: use braces to clarifyR \underset{A \theta B}{\Join}_{\text{R}} S 或者
        • 全外连接(Full Outer Join):返回两个关系中任一关系的所有元组,无论另一个关系中是否有匹配的元组。如果另一个关系中没有匹配的元组,则结果中对应的字段为NULL
          • 表示:Double subscripts: use braces to clarifyR \underset{A \theta B}{\Join}_{\text{FULL}} S 或者
  7. 笛卡尔积(Cartesian Product)

    • 符号:×
    • 作用:将两个关系中的每个元组与另一个关系中的每个元组配对,形成所有可能的组合。
    • 表示:R × S,表示关系R和关系S的笛卡尔积。
  8. 除(Division)

    • 符号:÷
    • 作用:找出能够与第二个关系中所有元组配对的第一个关系中的元组。
    • 表示:R ÷ S,表示关系R中能够与关系S中所有元组配对的元组。

简单理解:

  • 选择是取行,投影是取列。
  • 自然连接中,如果两个表有相同的列名,那两个表相同列名的列,具体值也要相同,才能配对。所以左右表都有可能会删去一些不匹配的行。
  • 左外连接中,左边表的所有行都会被保留,即使右边表中没有匹配的行,此时右边表对应的位置会用NULL填充。
  • 右外连接同理。
  • 全外连接中,左右两边表的所有行都会被保留,无论是不是匹配,当有一边没有匹配时,那一边对应的位置会用NULL填充。
  • 笛卡尔积就是两个表直接不由分说地连, 大小的表A和 大小的的表B,笛卡尔积得到的表C,与连接不同。
  • 除如图:图片

关系运算的sql表示

  1. 并(Union)

    1
    2
    3
    SELECT column_name(s) FROM table1
    UNION
    SELECT column_name(s) FROM table2;
  2. 交(Intersection)

    1
    2
    3
    SELECT column_name(s) FROM table1
    INTERSECT
    SELECT column_name(s) FROM table2;
  3. 差(Difference)

    1
    2
    3
    SELECT column_name(s) FROM table1
    EXCEPT
    SELECT column_name(s) FROM table2;
  4. 选择(Selection)

    1
    2
    SELECT * FROM table
    WHERE condition;
  5. 投影(Projection)

    1
    SELECT column_names FROM table;
  1. 连接(Join)
  • 自然连接(Natural Join)

    1
    2
    SELECT * FROM table1
    NATURAL JOIN table2;
  • 条件连接(θ-连接)

    1
    2
    SELECT * FROM table1
    JOIN table2 ON condition;
  • 外连接(Outer Join)

    • 左外连接(Left Outer Join)

      1
      2
      SELECT * FROM table1
      LEFT JOIN table2 ON condition;
    • 右外连接(Right Outer Join)

      1
      2
      SELECT * FROM table1
      RIGHT JOIN table2 ON condition;
    • 全外连接(Full Outer Join)

      1
      2
      SELECT * FROM table1
      FULL JOIN table2 ON condition;
  1. 笛卡尔积(Cartesian Product)

    1
    SELECT * FROM table1, table2;
  2. 除(Division)

    1
    2
    3
    4
    5
    SELECT column_names FROM table1
    WHERE NOT EXISTS (
    SELECT * FROM table2
    WHERE table1.column = table2.column
    );

习题

学生数据库

已知数据库

  1. 学生表S(Sno, Sname, Ssex, Sage, Sdept);
  2. 课程表C(Cno, Cname, Cpno, Ccredit);
  3. 学生选课表SC(Sno, Cno, Grade);

完成:

  1. 检索选修课程名为“数学”的学生的学号和姓名。
  2. 检索至少选修了课程号为 1 和 3 的学生的学号。
  3. 检索选修了“操作系统”或“数据库”课程的学生的学号和姓名。
  4. 检索年龄在 18~20 之间(含 18 和 20)的女生的学号、姓名及年龄。
  5. 检索选修了“数据库”课程的学生的学号、姓名及成绩。
  6. 检索选修了全部课程的学生的姓名所在系。
  7. 检索选修课程包括 1042 学生所学课程的学生的学号。
  8. 检索不选修 2 课程的学生的姓名和所在系。

My answer:
打latex也太难了吧,我直接开始歪歪地手写
图片

关系数据库标准语言SQL

视图在数据字典中保存的是视图定义

关系数据库编程

关系数据库安全和保护

关系数据库的规范化理论

关系模式中可能存在的冗余和异常问题

  1. 数据冗余
  2. 不一致性
  3. 插入异常
  4. 删除异常

    函数依赖

    定义

  5. 函数依赖:设 为任一给定关系,如果对于 中属性 的每一个值, 中的属性 只有唯一值与之对应,则称 函数决定 ,或 函数依赖于 X,记作 。其中,X 称为决定因素。反之,对于关系 中的属性 ,若 不能函数决定 Y,则其符号记作
  6. 平凡的函数依赖:设 是一个函数依赖,若 ,则称 是一个平凡的函数依赖
  7. 完全函数依赖:设 是一个函数依赖,并且对于任何 都不成立,则称 是一个完全函数依赖,记作
  8. 部分函数依赖:设 是一个函数依赖,但不是完全函数依赖,则称 是一个部分函数依赖,记作
  9. 传递函数依赖:设 是一个关系模式,,如果 ,且 ,则称 传递函数依赖
  10. 候选码:设 为任一给定关系模式, 为其所含的全部属性集合, 的子集,若有完全函数依赖 ,则 的一个候选码
  11. 主属性和非主属性:包含在任何一个候选码中的属性为主属性,否则为非主属性。

理解

  1. 普通函数依赖(X→Y)
    想象你的身份证号码(X)就像一把万能钥匙,它能直接确定你的姓名(Y)、性别、出生地。只要知道身份证号,其他信息都能唯一确定。
    例如:学号→姓名,就像每个学号对应唯一的学生。

  2. 平凡依赖 vs 非平凡依赖

    • 平凡就像「已知父亲名字,自然知道家族姓氏」(因为姓氏已经是父亲名字的一部分)
    • 非平凡像「快递单号与包裹信息」,单号能唯一确定收件人的电话(例如单号 SF123456 对应电话 13800001111),但电话不是单号的子集,这也是​​非平凡函数依赖
  3. 完全依赖 vs 部分依赖
    完全依赖就像「用完整钥匙开锁」:

    • 成绩完全依赖(学号+课程号)组合,单独学号或课程号都不够

    部分依赖像「用半截钥匙就能开锁」:

    • 如果课程名称只依赖课程号(而课程号是主键的一部分),就是部分依赖
  4. 传递依赖(连锁反应)
    学号→系号→系主任,系主任像被「间接遥控」确定。这会导致数据冗余(多个学生重复存储系主任信息)

  • 候选码就像「能开所有锁的最小钥匙组合」:

    • 比如(学号+课程号)组合才能确定成绩,单独一个都不行
  • 主属性是所有候选码中的零件:

    • 如果候选码是学号,那么学号就是主属性;如果候选码是(学号+身份证号),两者都是主属性

范式

第一范式(1NF)

如果关系模式 的每一个 属性对应的域值都是不可再分的,称模式 属于第一范式,记作 。若数据库模式 中的每个关系模式都是 ,则数据库模式

最基本的要求,就是表中的每个属性都不可再分。例如,学生信息表中,每个学生的姓名、年龄、性别等都是不可再分的。

第二范式(2NF)

如果关系模式 ,并且每个非主属性都完全函数依赖于 的码,则

不能有部分依赖。例如,在选课表中,学生成绩应该依赖于学号和课程号的组合,而不是单独依赖学号或课程号。

第三范式(3NF)

关系模式 R 中若不存在这样的码 、属性组 及非主属性 ,使得 成立,则称

例如,学生表中的成绩不能依赖于学生的姓名,因为姓名不是码。

Boyce-Codd范式(BCNF)

,而且R中没有任何属性传递函数依赖于R中的码,则关系模式

第四范式(4NF)

了解一下就可以了。

第五范式(5NF)

了解一下就可以了。

理解

  1. 1NF(基础版)
    要求:每个字段都是最小单元,不能拆。
    错误示范:把「联系电话」写成 “13800001111,13800002222”(应拆分成多行)

  2. 2NF(消灭半吊子依赖)
    必须消灭部分依赖。比如选课表中:

    • 错误:把课程名称和成绩都放在同一张表(课程名称只依赖课程号,不依赖学号)

    • 正确:拆分成「选课表(学号+课程号+成绩)」和「课程表(课程号+课程名称)」

  3. 3NF(斩断连锁依赖)
    禁止传递依赖。比如学生表里直接存系主任名字:
    • 错误:学生表包含系号→系主任
    • 正确:拆分成「学生表(学号+系号)」和「院系表(系号+系主任)」
  4. BCNF(加强版3NF)
    连主属性都不能有传递依赖。举个极端例子:
    • 假设每个老师只教一门课,每门课有多个老师
    • 错误表:(老师ID,课程)主键是老师ID,但课程→教室(课程不是主键)
    • 正确:拆分成「老师-课程表」和「课程-教室表」

举个综合例子(学生选课系统):
原始混乱表
| 学号 | 姓名 | 课程号 | 课程名 | 成绩 | 系名 | 系主任 |
|—-|—-|—-|—-|—-|—-|—-|
| 001 | 张三 | C01 | 数学 | 90 | 计算机系 | 李主任 |

问题分析:

  1. 课程名只依赖课程号(违反2NF)
  2. 系主任依赖系名,系名依赖学号(传递依赖,违反3NF)

助记小漫画(但是记的可能不是数据库知识点)

</details>

规范化后:

  • 学生表(学号,姓名,系名)3NF

  • 课程表(课程号,课程名)2NF

  • 选课表(学号,课程号,成绩)2NF

  • 院系表(系名,系主任)3NF

这样修改后,更新系主任信息只需要修改院系表中的一个位置,避免了数据冗余和更新异常。

模式分解

习题

2021上半年软考 42题

给定关系R(U,F),其中U={A,B,C,D,E,H},F={(A→B,B→DH,A→H,C→E)}。关系有( ),F中( )。

问题1:

  • [ ] A. 1个候选码A
  • [ ] B. 2个候选码A、B
  • [x] C. 1个候选码AC
  • [ ] D. 2个候选码A、C

问题2:

  • [ ] A. 不存在传递依赖,但存在冗余函数依赖
  • [ ] B. 既不存在传递依赖,也不存在冗余函数依赖
  • [ ] C. 存在传递依赖A→D和A→H,但不存在冗余函数依赖
  • [x] D. 存在传递依赖A→D和A→H,并且还存在冗余函数依赖

算法

日期题: datetime

日期差值填空

众所周知,2025 年是完全平方年,因为
定义一个年份 是完全平方年当且仅当存在一个正整数 使得
今天是 2025 年 3 月 29 日,现在我们想知道距离下一个完全平方年的 1 月 1 日还有几天(即从 2025 年 3 月 29 日 0 时到下次完全平方年的 1 月 1 日 0 时,例如:从 3 月 29 日 0 时到 3 月 30 日 0 时算 1 天)。

1
2
3
4
from datetime import datetime as dt
a=dt(2025,3,29,0,0,0)
b=dt(46**2,1,1,0,0,0)
print((b-a).days)

P10385 [蓝桥杯 2024 省 A] 艺术与篮球

小蓝决定根据日期的笔画数来安排自己的练习。首先,他会将当天的日期按照 YYYYMMDD 的格式
转换成一个 位数,然后将这 位数对应到汉字上,计算这些汉字的总笔画数。如果总笔画数超过 ,他就去练习篮球;如果总笔画数不超过 ,他就去练习书法。
例如,在 日这天,日期可表示为一个 位数字 ,其转换为汉字是“二零二四零一零一”。日期的总笔画数为 ,因此在这天,小蓝会去练习书法。
以下是汉字的笔画数对照表:

汉字 笔画数 汉字 笔画数

现在,请你帮助小蓝统计一下,在 日到
这段时间内,小蓝有多少天是在练习篮球?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from datetime import datetime,timedelta
a=datetime(2000,1,1,0,0,0)
b=datetime(2024,4,13,0,0,0)
c=a
d=timedelta(days=1)
bh=[13,1,2,3,5,4,4,2,2,2]
s=0
def cnt(x,n):
ret=0
for i in range(n):
ret+=bh[x%10]
x//=10 # 注意python除法
return ret

while c<=b:
s+=1 if cnt(c.year,4)+cnt(c.month,2)+cnt(c.day,2)>50 else 0
c+=d

print(s)

大数/高精度题: decimal

最高位之和

对于正整数 ,设 在十进制下的最高非零位的值, 在十进制下的最高非零位的值,求所有可能的作为 的值的和。相同的值只计算一次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from decimal import Decimal
two=Decimal('2')
five=Decimal('5')
s=set()
def high(x):
while x>9:
x//=10
return x

for i in range(50000):
try:
s.add(high(two)*high(five))
two*=2
five*=5
# print(two,five)
except Exception as e:
# print(str(e))
break
res=0
for i in s:
res+=i
print(res)

对拍

待测程序

待测程序test.cpp

1
2
3
4
5
6
7
8
9
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen("input.txt","r",stdin);
freopen("output1.txt","w",stdout);
//待测程序
return 0;
}

对拍程序

对拍程序bl.cpp

1
2
3
4
5
6
7
8
9
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen("input.txt","r",stdin);
freopen("output2.txt","w",stdout);
//待测程序
return 0;
}

Python简易评测机

没用过,先放一个在这儿
python简易对拍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import os
import random
import subprocess
import time
import filecmp

def test():
with open("input.txt", "w") as f:
'''
生成随机数据,例
n = random.randint(1, 100)
f.write(f"{n}\n")
for _ in range(n):
l = random.randint(1, 100)
r = random.randint(1, 100)
f.write(f"{l} {r}\n")
'''
start_time=time.time()
subprocess.run(["test.exe"], shell=True) # 测试
print(f"用时{time.time()-start_time:.3f}s")
subprocess.run(["bl.exe"], shell=True) # 对拍
return filecmp.cmp("output1.txt", "output2.txt")

random.seed(time.time())
for i in range(100): # 测试数量
print(f"运行测试例 {i}...")
if not test():
print("测试例 {i} 失败")
exit(0)
print("通过")

参考:https://blog.csdn.net/Mibbp/article/details/124012372

算了,寒假里做几道放几道呗

P8740 [蓝桥杯 2021 省 A] 填空问题

题目描述

试题 A:卡片

【问题描述】

小蓝有很多数字卡片,每张卡片上都是数字

小蓝准备用这些卡片来拼一些数,他想从 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。

小蓝想知道自己能从 拼到多少。

例如,当小蓝有 张卡片,其中 张,则小蓝可以拼出 ,但是拼 时卡片 已经只有一张了,不够拼出

现在小蓝手里有 的卡片各 张,共 张,请问小蓝可以从 拼到多少?

提示:建议使用计算机编程解决问题。

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

试题 B:直线

【问题描述】

在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。

给定平面上 个整点 ,即横坐标是 (包含 ) 之间的整数、纵坐标是 (包含 ) 之间的整数的点。这些点一共确定了 条不同的直线。

给定平面上 个整点 ,即横坐标是 (包含 ) 之间的整数、纵坐标是 (包含 ) 之间的整数的点。请问这些点一共确定了多少条不同的直线。

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

试题 C :货物摆放

【问题描述】

小蓝有一个超大的仓库,可以摆放很多货物。

现在,小蓝有 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、 宽、高。

小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆 的货物,满足

给定 ,请问有多少种堆放货物的方案满足要求。

例如,当 时,有以下 种方案:

请问,当 (注意有 位数字) 时,总共有多少种方案?

提示:建议使用计算机编程解决问题。

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

试题 D:路径

【问题描述】

小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。

小蓝的图由 个结点组成,依次编号

对于两个不同的结点 ,如果 的差的绝对值大于 ,则两个结点之间没有边相连; 如果 的差的绝对值小于等于 ,则两个点之间有一条长度为 的最小公倍数的无向边相连。

例如:结点 和结点 之间没有边相连; 结点 和结点 之间有一条无向边,长度为 ; 结点 和结点 之间有一条无向边,长度为

请计算,结点 和结点 之间的最短路径长度是多少。

提示:建议使用计算机编程解决问题。

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

试题 E:回路计数

【问题描述】

蓝桥学院由 栋教学楼组成,教学楼编号 。对于两栋教学楼 ,当 互质时, 之间有一条走廊直接相连,两个方向皆可通行,否则没有直接连接的走廊。

小蓝现在在第一栋教学楼,他想要访问每栋教学楼正好一次,最终回到第一栋教学楼(即走一条哈密尔顿回路),请问他有多少种不同的访问方案? 两个访问方案不同是指存在某个 ,小蓝在两个访问方法中访问完教学楼 后访问了不同的教学楼。

提示:建议使用计算机编程解决问题。

解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
using ll = long long;
using ull = unsigned long long;
//==================== 1 ====================
void solve1()
{
int a[10];
for (int i = 0; i <= 9; i++)
a[i] = 2021;
for (int i = 1;; i++)
{
for (int j = i; j; j /= 10)
{
if (a[j % 10] == 0)
{
cout << i - 1 << endl;
return;
}
--a[j % 10];
}
}
}
//==================== 2 ====================
int gcd(int x, int y)
{
return x % y == 0 ? y : gcd(y, x % y);
}
void solve2()
{
int n = 20, m = 21;
ull ans = 0ll; // row,col
for (int a = 1; a < n; a++)
{
for (int b = 1; b < m; b++)
{
if (gcd(a, b) != 1)
continue;
ans += (n - a) * (m - b);
if (a * 2 <= n && b * 2 <= n)
{
ans -= (n - 2 * a) * (m - 2 * b);
}
}
}
ans *= 2;
ans += (n + m);
cout << ans << endl;
}
//==================== 3 ====================
typedef pair<ull, ull> pp;
ull ans3 = 0;
map<pp, bool> mp;
vector<ull> yz; // 因子
void dfs3(pp p, int d)
{
if (d == yz.size())
{
if (!mp[p])
{
mp[p] = true;
ans3++;
}
return;
}
dfs3(pp(p.first, p.second), d + 1);
dfs3(pp(p.first * yz[d], p.second), d + 1);
dfs3(pp(p.first, p.second * yz[d]), d + 1);
}
void solve3()
{
ull n = 2021041820210418;
for (int i = 2; i <= n;)
{
if (n % i == 0)
{
// cout<<i<<',';
yz.push_back(i);
n /= i;
}
else
{
i++;
}
}
// 2,3,3,3,17,131,2857,5882353
dfs3(pp(1, 1), 0);
cout << ans3 << endl;
}
//==================== 4 ====================
typedef pair<int, int> pint;
void solve4()
{
int n = 2021;
vector<vector<pint>> g(2022);
for (int i = 1; i <= n; i++)
{
for (int j = i + 1; j <= i + 21 && j <= n; j++)
{
int w = i * j / gcd(i, j);
g[i].push_back(pint(w, j));
g[j].push_back(pint(w, i));
}
}
// dijsktra
const int inf = INT_MAX;
vector<int> dis(n + 1, inf);
vector<bool> vis(n + 1, false);
dis[1] = 0;
priority_queue<pint, vector<pint>, greater<>> pq;
pq.push(pint(0, 1));
while (!pq.empty())
{
int u = pq.top().second;
pq.pop();
if (!vis[u])
{
vis[u] = true;
for (auto [w, v] : g[u])
{
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if (!vis[v])
pq.push(pint(dis[v], v));
}
}
}
}
cout << dis[2021] << endl;
}
//==================== 5 ====================
ull ans5;
int ok;
bool have[22][22];
ull f[1 << 21][22]; // 走的序列,到下一个点
void solve5()
{
for (int i = 1; i < 21; i++)
{
for (int j = i + 1; j <= 21; j++)
{
if (gcd(i, j) == 1)
{
have[i][j] = have[j][i] = true;
}
}
}
ok =(1 << 21)-1;// 2,097,151
f[1][1]=1;
for (int c = 1; c <= ok; c++)
{
for (int i = 1; i <= 21; i++)
{
if (c & (1 << (i - 1)))
for (int j = 1; j <= 21; j++)
{
if (!(c & (1 << (j - 1))) && have[i][j])
f[c | (1 << (j - 1))][j] += f[c][i];
}
}
}
for (int i = 1; i <= 21; i++)
{
ans5 += f[ok][i];
}
cout << ans5 << endl;
}
//==================== answer ====================
signed main()
{
string ans[] = {
"3181", // 双引号中替换为 A 题的答案
"40257", // 双引号中替换为 B 题的答案
"2430", // 双引号中替换为 C 题的答案
"10266837", // 双引号中替换为 D 题的答案
"881012367360", // 双引号中替换为 E 题的答案
};
char T;
cin >> T;
cout << ans[T - 'A'] << endl;
return 0;
}

P8742 [蓝桥杯 2021 省 AB] 砝码称重

题目描述

你有一架天平和 个砝码, 这 个砝码重量依次是 。 请你计算一共可以称出多少种不同的重量?

注意砝码可以放在天平两边。

输入格式

输入的第一行包含一个整数

第二行包含 个整数:

输出格式

输出一个整数代表答案。

输入输出样例 #1

输入 #1

1
2
3
1 4 6

输出 #1

1
10

说明/提示

【样例说明】

能称出的 10 种重量是:

【评测用例规模与约定】

对于 的评测用例,

对于所有评测用例, 个砝码总重不超过

蓝桥杯 2021 第一轮省赛 A 组 F 题(B 组 G 题)。

解法

01背包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int f[101][N];
signed main()
{
int n, w, sum = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &w);
sum += w;
for (int j = sum; j; j--)
if (f[i - 1][j])
f[i][j] = f[i][abs(j - w)] = f[i][j + w] = 1;
f[i][w] = 1;
}
int ans = 0;
for (int j = 1; j <= sum; j++)
ans += f[n][j];
printf("%d\n", ans);
return 0;
}

P8743 [蓝桥杯 2021 省 A] 异或数列

题目描述

Alice 和 Bob 正在玩一个异或数列的游戏。初始时,Alice 和 Bob 分别有一个整数 , 有一个给定的长度为 的公共数列

Alice 和 Bob 轮流操作,Alice 先手,每步可以在以下两种选项中选一种:

选项 1: 从数列中选一个 给 Alice 的数异或上, 或者说令 变为 。(其中 表示按位异或)

选项 2: 从数列中选一个 给 Bob 的数异或上,或者说令 变为

每个数 都只能用一次, 当所有 均被使用后( 轮后)游戏结束。游戏结束时, 拥有的数比较大的一方获胜,如果双方数值相同,即为平手。

现在双方都足够聪明,都采用最优策略,请问谁能获胜?

输入格式

每个评测用例包含多组询问。询问之间彼此独立。

输入的第一行包含一个整数 ,表示询问数。

接下来 行每行包含一组询问。其中第 行的第一个整数 表示数列长度,随后 个整数 表示数列中的每个数。

输出格式

输出 行,依次对应每组询问的答案。

每行包含一个整数 分别表示 Alice 胜、平局或败。

输入输出样例 #1

输入 #1

1
2
3
4
5
4
1 1
1 0
2 2 1
7 992438 1006399 781139 985280 4729 872779 563580

输出 #1

1
2
3
4
1
0
1
1

说明/提示

对于所有评测用例,

蓝桥杯 2021 第一轮省赛 A 组 G 题。

解法

转换成二进制,对于某一位,如果它是1,则反转这一位答案。0对答案无影响。奇数个1异或得1,偶数个1异或得0

  • 当1有偶数个时,偶数=偶数+偶数,这一位平手。
  • 当1有奇数个时,奇数=奇数+偶数,两人都想办法获得奇数个1。
    • 只有一个1,Alice直接选,Alice win
    • 当0有偶数个,两人相抵,Alice win
    • 当0有奇数个,Bob选一个0,反转局面,Bob win

例:1 1 1 0 0 0
Alice:1
Bob:0(反转先手)
Alice:0
Bob:0
Alice:1(被迫)
Bob:Alice 1
Bob win

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <bits/stdc++.h>
using namespace std;
signed main()
{
int t, n, x, cnt[22];
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
memset(cnt, 0, sizeof(cnt));
for (int i = 0; i < n; i++)
{
scanf("%d", &x);
for (int b = 0; x; b++)
{
if (x & 1)
cnt[b]++;
x >>= 1;
}
}
int win = 0;
for (int i = 20; i >= 0; i--)
{
if (cnt[i] & 1)
{
if (cnt[i] == 1)
win = 1;
else
win = n & 1 ? 1 : -1; // 偶数个0Alice win
break;
}
}
printf("%d\n", win);
}
return 0;
}
/*

*/

P8744 [蓝桥杯 2021 省 A] 左孩子右兄弟

题目描述

对于一棵多叉树,我们可以通过“左孩子右兄弟”表示法,将其转化成一棵二叉树。

如果我们认为每个结点的子结点是无序的,那么得到的二叉树可能不唯一。换句话说,每个结点可以选任意子结点作为左孩子,并按任意顺序连接右兄弟。

给定一棵包含 个结点的多叉树,结点从 编号,其中 号结点是根,每个结点的父结点的编号比自己的编号小。请你计算其通过”左孩子右兄弟”表示法转化成的二叉树,高度最高是多少。(只有根结点这一个结点的树高度为

例如如下的多叉树:

可能有以下 种 (这里只列出 种, 并不是全部) 不同的 “左孩子右兄弟” 表示:

其中最后一种高度最高, 为

输入格式

输入的第一行包含一个整数

以下 行, 每行包含一个整数, 依次表示 号结点的父结点编号。

输出格式

输出一个整数表示答案。

输入输出样例 #1

输入 #1

1
2
3
4
5
5
1
1
1
2

输出 #1

1
4

说明/提示

对于 的评测用例,;

对于所有评测用例,

蓝桥杯 2021 第一轮省赛 A 组 H 题。

解法

dfs
最大答案=孩子数+孩子中的最大答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n;
vector<vector<int>> child(N);
int dfs(int u)
{
int ret = 0;
for (int v : child[u])
ret = max(ret, dfs(v));
return ret + child[u].size();
}
signed main()
{
scanf("%d", &n);
int r;
for (int i = 2; i <= n; i++)
{
scanf("%d", &r);
child[r].push_back(i);
}
printf("%d", dfs(1));
return 0;
}


P8745 [蓝桥杯 2021 省 AB] 括号序列

题目描述

给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。

例如,对于括号序列 (((),只需要添加两个括号就能让其合法,有以下几种不同的添加结果:()()()()(())(())()(()())((()))

输入格式

输入一行包含一个字符串 ,表示给定的括号序列,序列中只有左括号和右括号。

输出格式

输出一个整数表示答案,答案可能很大,请输出答案除以 (即 )的余数。

输入输出样例 #1

输入 #1

1
((()

输出 #1

1
5

说明/提示

对于 的评测用例,

对于所有评测用例,

蓝桥杯 2021 第一轮省赛 A 组 I 题(B 组 J 题)。

解法

python生成代码

1
2
3
4
5
6
7
8
a=['(',')']
from random import randint
def f():
l=randint(5,12)
for i in range(l):
print(a[randint(0,1)],end='')
print()
f()

嗯。。。后面没有做了(逃)

一雪2024的前耻,今年报销了300大洋报名费!慢慢复盘。

考时黑客不会优化,最后一题只写完了拖布,拓步,托……反正就是那个什么什么排序啦!目前黑客已经优化,最后三题还没复盘。

洛谷评测

注意事项

  • 这里的题解偷懒了,实际上考试时不要用ios::sync_with_stdio(false);cin.tie(nullptr), cout.tie(nullptr);,直接用scanfprintf最保险
  • 注意数据范围,注意用long long或者unsigned long long的情况
  • 一定记得return 0
  • 注意devcpp开栈和c++版本
  • 某些特殊的填空题可以用python写,改天新开一篇博文写
  • 写一题交一题
  • 拿不要死磕一道题,尽可能每道题都暴力骗到分。实在不行直接输出样例。

P12138 [蓝桥杯 2025 省 A] 寻找质数

题目背景

本站蓝桥杯 2025 省赛测试数据均为洛谷自造,与官方数据可能存在差异,仅供学习参考。

题目描述

如果一个正整数只能被 和它本身两个数整除,就称为一个质数。最小的几个质数依次是

请问,第 个质数是多少?

输入格式

输出格式

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只需要编写一个程序输出这个整数,输出多余的内容将无法得分。

解法

get 5/5分
暴力就好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int cnt = 1, n = 1;
while (cnt < 2025)
{
n += 2;
bool prime = true;
for (int i = 3; i < n; i += 2)
{
if (n % i == 0)
{
prime = false;
break;
}
}
if (prime)
{
++cnt;
}
}
cout << n << endl;

P12139 [蓝桥杯 2025 省 A] 黑白棋

题目描述

小蓝最近迷上了一款名为“黑白棋填充”的游戏。该游戏在一个方形网格棋盘上进行,其中部分格子已经填有黑色或白色的棋子,而其他格子为空,等待玩家填入棋子。

游戏规则是,玩家需要按照以下规则填满整个棋盘,才能算作胜利:

  1. 黑白棋子数量均等
    在每一行和每一列中,黑色棋子和白色棋子的数量必须相等。
  2. 相邻棋子限制
    在棋盘的任何一行或一列中,不能有超过两个相同颜色的棋子连续排列(即不允许出现“黑黑黑”或“白白白”的情况)。
  3. 行列唯一性
    每一行的棋子排列方式必须是唯一的,不能与棋盘中的任何其他行完全相同。
    每一列的棋子排列方式必须是唯一的,不能与棋盘中的任何其他列完全相同。
    行与列之间的棋子排列不作比较,即行可以与列相同,无需满足行列间的唯一性。

现在有一个 的棋盘,如上图所示,其中部分格子已填入棋子(黑色或白色),其余格子需要你填充,题目保证有唯一解。

请给出唯一的正确解,并按照以下格式输出答案:

  • 黑色棋子用 表示,白色棋子用 表示。
  • 从左到右、从上到下的顺序,依次遍历棋盘上的所有格子,并将这些值拼接成一个长度为 的字符串。

例如,假设最终填充完成后的棋盘如下(仅为示例,并非真实答案):

1
2
3
4
5
6
1 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 0 0
0 0 1 1 0 0
0 0 1 1 1 1

则输出结果应为:100000000000000000001000001100001111

输入格式

输出格式

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只需要编写一个程序输出这个整数,输出多余的内容将无法得分。

解法

get 5/5分
考试时第一反应是打excel表格,好吧。其实dfs稍微剪枝一下就可以。狠狠暴力!忘情地暴力!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <bits/stdc++.h>

using namespace std;
using ll = long long;
int board[][6] = {
{1, 0, 2, 0, 2, 2},
{2, 2, 2, 0, 2, 2},
{2, 2, 2, 2, 0, 0},
{2, 2, 2, 2, 2, 2},
{2, 2, 1, 2, 2, 1},
{2, 0, 2, 2, 1, 2}};
// 颜色,对应剩余棋子数
int row[2][6] = {{3, 3, 3, 3, 3, 3}, {3, 3, 3, 3, 3, 3}},
col[2][6] = {{3, 3, 3, 3, 3, 3}, {3, 3, 3, 3, 3, 3}};
void dfs(int r, int c)
{
if (r == 5) // 列尾
{
//每一列的棋子排列方式必须是唯一的,不能与棋盘中的任何其他列完全相同。
for (int j = 0; j < c - 1; ++j)
{
bool ok = false;
for (int i = 0; i < 6; ++i)
{
if (board[i][j] != board[i][c - 1])
{
ok = true;
break;
}
}
if (!ok)
return;
}
}
if (c == 6) // 行尾
{
// 每一行的棋子排列方式必须是唯一的,不能与棋盘中的任何其他行完全相同。
for (int i = 0; i < r; ++i)
{
bool ok = false;
for (int j = 0; j < 6; ++j)
{
if (board[i][j] != board[r][j])
{
ok = true;
break;
}
}
if (!ok)
return;
}
++r;
c = 0;
}
if (r == 6) // 列尾
{
for (int i = 0; i < 6; ++i)
{
for (int j = 0; j < 6; ++j)
{
cout << board[i][j];
}
// cout << endl;
}
exit(0);
}
// 该位置为空
if (board[r][c] == 2)
{
for (int color = 0; color < 2; color++)
{
// 每一行和每一列中,黑色棋子和白色棋子的数量必须相等
if (row[color][r] <= 0 || col[color][c] <= 0)
continue;
// 在棋盘的任何一行或一列中,不能有超过两个相同颜色的棋子连续排列(即不允许出现“黑黑黑”或“白白白”的情况)。
if (r >= 2 && color == board[r - 1][c] && color == board[r - 2][c])
continue;
if (c >= 2 && color == board[r][c - 1] && color == board[r][c - 2])
continue;
--row[color][r];
--col[color][c];
board[r][c] = color;
dfs(r, c + 1);
++row[color][r];
++col[color][c];
}
board[r][c] = 2;
}
else // 该位置已经有棋子
{
int color = board[r][c];
// 每一行和每一列中,黑色棋子和白色棋子的数量必须相等
if (row[color][r] <= 0 || col[color][c] <= 0)
return;
// 在棋盘的任何一行或一列中,不能有超过两个相同颜色的棋子连续排列(即不允许出现“黑黑黑”或“白白白”的情况)。
if (r >= 2 && color == board[r - 1][c] && color == board[r - 2][c])
return;
if (c >= 2 && color == board[r][c - 1] && color == board[r][c - 2])
return;
--row[color][r];
--col[color][c];
dfs(r, c + 1);
++row[color][r];
++col[color][c];
}
}
signed main()
{
dfs(0, 0);//101001010011101100010110011001100110
return 0;
}

P12140 [蓝桥杯 2025 省 A] 抽奖

题目背景

本站蓝桥杯 2025 省赛测试数据均为洛谷自造,与官方数据可能存在差异,仅供学习参考。

题目描述

LQ 商场为了回馈广大用户,为在此消费的用户提供了抽奖机会:抽奖机有三个转轮,每个转轮上都分布有 个数字图案,标号为 ,按照从 顺序转动,当转到第 个图案时会从第一个继续开始。奖项如下:

  1. 三个相同的图案,积分
  2. 两个相同的图案,积分
  3. 三个数字图案,从左到右连续(例如 ),积分
  4. 三个数字图案,经过顺序调整后连续(例如 ),积分

抽奖机处于初始状态,三个转轮都处于第一个位置。每次开始抽奖,都会产生三个对应的随机数 ,表示第 个转轮会向后转动 次停下。下次抽奖时,转轮会从上一次转动后的位置开始继续转动。

注意,一次抽奖最多只能获得一次积分,如果同时命中多个奖项,以积分最大的那个奖项为准。

请问,如果执行 次抽奖,总积分值是多少?

输入格式

输入的第一行包含一个正整数 ,表示转轮大小。

第二行包含 个正整数 ,依次表示第一个转轮上的数字图案,相邻整数之间使用一个空格分隔。

第三行包含 个正整数 ,依次表示第二个转轮上的数字图案,相邻整数之间使用一个空格分隔。

第四行包含 个正整数 ,依次表示第三个转轮上的数字图案,相邻整数之间使用一个空格分隔。

第五行包含一个整数 ,表示抽奖次数。

接下来 行,每行包含三个正整数 ,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案,即 次抽奖累计获得的积分的值。

输入输出样例 #1

输入 #1

1
2
3
4
5
6
7
8
4
3 2 4 1
2 2 2 2
4 3 0 9
3
4 4 4
3 1 1
40 39 2

输出 #1

1
300

说明/提示

样例说明

  • 第一次抽奖:三个转轮都转动 次,到达位置 ,数字图案为 ,积分
  • 第二次抽奖:数字图案为 ,积分
  • 第三次抽奖:数字图案为 ,积分不增加。

评测用例规模与约定

  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于所有评测用例,

解法

大模拟,暴力。注意转盘用%运算模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <bits/stdc++.h>
using namespace std;
#define N 1005

int n, m, d, res = 0;
int arr[3][N];
int pos[3], jiang[3];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);

cin >> n;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < n; ++j)
cin >> arr[i][j];
cin >> m;
while (m--)
{
for (int i = 0; i < 3; ++i)
{
cin >> d;
pos[i] = (pos[i] + d) % n;
jiang[i] = arr[i][pos[i]];
}
if (jiang[0] == jiang[1])
{
if (jiang[0] == jiang[2])
res += 200;
else
res += 100;
}
else if (jiang[0] == jiang[2] || jiang[1] == jiang[2])
{
res += 100;
}
else if (jiang[0] + 1 == jiang[1] && jiang[0] + 2 == jiang[2])
{
res += 200;
}
else
{
sort(jiang, jiang + 3);
if (jiang[0] + 1 == jiang[1] && jiang[0] + 2 == jiang[2])
{
res += 100;
}
}
}
cout << res << endl;
return 0;
}

P12141 [蓝桥杯 2025 省 A] 红黑树

题目描述

小蓝最近学习了红黑树,红黑树是一种特殊的二叉树,树上的结点有两种类型:红色结点和黑色结点。

小蓝在脑海中构造出一棵红黑树,构造方式如下:

  1. 根结点是一个红色结点;
  2. 如果当前结点 是红色结点,那么左子结点 是红色结点,右子结点 是黑色结点;
  3. 如果当前结点 是黑色结点,那么左子结点 是黑色结点,右子结点 是红色结点;

此二叉树前几层的形态如下图所示:

小蓝会从树上随机挑选结点,请你帮忙判断他选出的是红色结点还是黑色结点。

输入格式

输入的第一行包含一个正整数 ,表示小蓝挑选的结点数。

接下来 行,每行包含两个正整数 ,用一个空格分隔,表示小蓝挑选的结点是第 行(从上往下数)第 个(从左往右数)结点。

输出格式

输出 行,每行包含一个字符串,依次表示小蓝每次挑选的结点的答案。RED 表示红色结点,BLACK 表示黑色结点。

输入输出样例 #1

输入 #1

1
2
3
2
1 1
2 2

输出 #1

1
2
RED
BLACK

说明/提示

样例说明

  • 第一行第一个结点为根结点,红色;
  • 第二行第二个结点为黑色结点。

评测用例规模与约定

  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于所有评测用例,

解法

get 10/10
使用瞪眼法,一眼顶针,红黑树看出是异或运算,多往下画两行就发现,颜色和行数无关。把红和黑分别看作0和1,颜色就是异或1的运算。
红黑树示意图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int n, m, k;
cin >> m;
while (m--)
{
cin >> n >> k;
int a = 0;
--k;
while (k)
{
a ^= (k & 1);
k >>= 1;
}
if (a)
cout << "BLACK" << endl;
else
cout << "RED" << endl;
}

P12142 [蓝桥杯 2025 省 A] 黑客

题目描述

小蓝正在两台电脑之间拷贝数据,数据是一个 大小的正整数矩阵,因此总共有 个由空格分开的整数,其中前两个整数分别为 。然而,有黑客入侵了小蓝的电脑,导致这 个正整数的顺序被打乱了。小蓝想知道最多可能有多少个不同的原矩阵。

两个矩阵相同当且仅当它们行数相同、列数相同,且每个位置上的数相同。

输入格式

输入的第一行包含一个正整数

第二行包含 个正整数 ,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。答案可能很大,请输出答案除以 的余数。

输入输出样例 #1

输入 #1

1
2
6
2 2 1 4 3 3

输出 #1

1
24

说明/提示

样例说明

可能的原矩阵情况包括:

  1. :有 种原矩阵:
  2. :有 种原矩阵;
  3. :有 种原矩阵;

总计 种。

评测用例规模与约定

  • 对于 的评测用例,
  • 对于所有评测用例,

解法

思路

不用管是不是二维矩阵,直接看作一维数矩阵。题目大意:当找到两个数 ,当 时,求剩余 个数有多少种不重复的排列,并对其求和。

考试时不知道带模的除法怎么做,只好开了 unsigned long long 并且打了个 22 以内的阶乘表,大概是拿 40% 的分了。

实际上,后面补习数论,模意义下的除法是这样的:

其中 是求 模意义下的逆元。这里数据量不大,可以套快速幂公式。

而这里的排列公式为:当有 个不相同的数 排列,对于每一个数 ,它的数量是 ,排列方式有 种。

豪!基础复习完毕。回到题目——

对于行数 和列数 ,当 时,求剩余 个数的排列方式数目。排列公式分母里要去掉一个 和一个 ,当两者相同时,就相当于去掉两个

对于一对“行数”和“列数”,上述排列公式的分母如下:

将分母带入排列公式:

最终答案表达式,即求和:

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <bits/stdc++.h>
using namespace std;
#define ll unsigned long long
#define N 500005
const int p = 1000000007;

int n, m;
unordered_map<ll, int> mp;//对每个数,对应的数量。unordered_map比map更高效
ll jc[N]; // 阶乘
ll inverse(ll a)//快速幂逆元
{
ll b = p - 2, ret = 1;
while (b)
{
if (b & 1)
ret = ret * a % p;
a = a * a % p;
b >>= 1;
}
return ret;
}
signed main()
{
jc[0] = jc[1] = 1;
for (int i = 2; i < N; ++i)
{
jc[i] = jc[i - 1] * i % p;
}
scanf("%d", &n);
m = n - 2;//矩阵的大小
ll a, b = 1, rc = 0;
for (int i = 0; i < n; ++i)
{
scanf("%lld", &a);
++mp[a];
}
for (auto i : mp)
{
b = b * jc[i.second] % p;
}
for (auto r : mp)
{
if (m % r.first != 0)
continue;
auto c = mp.find(m / r.first);
if (c == mp.end()) // 找不到两数相乘为n-2
continue;
if (r.first != c->first)
rc = (rc + r.second * c->second % p) % p;
else
rc = (rc + r.second * (r.second - 1) % p) % p;
}
cout << jc[n - 2] * inverse(b) % p * rc % p << endl;
return 0;
}

P12143 [蓝桥杯 2025 省 A] 好串的数目

题目描述

对于一个长度为 的字符串 来说,子串的定义是从中选出两个下标 ,这之间所有的字符组合起来的一个新的字符串: 就是其中一个子串。

现在给出一个只有数字字符 组成的数字字符串,小蓝想要知道在其所有的子串中,有多少个子串是好串。一个子串是好串,当且仅当它满足以下两个条件之一:

  1. 单字符子串一定是好串,即当子串长度为 时,它总是好串;
  2. 长度大于 时,可以拆分为两个连续非递减子串
    一个串 连续非递减子串是指,对于所有 ,满足 。即数字串中的每一个数字,要么等于上一个数字,要么等于上一个数字加 。例如 12233456 是连续非递减子串。

输入格式

输入一行包含一个字符串

输出格式

输出一行包含一个整数表示答案,即好串的数目。

输入输出样例 #1

输入 #1

1
12258

输出 #1

1
12

输入输出样例 #2

输入 #2

1
97856

输出 #2

1
13

说明/提示

样例说明 1

  • 长度为 的好串:12258,共 个;
  • 长度为 的好串:12222558,共 个;
  • 长度为 的好串:122225,共 个;
  • 长度为 的好串:1225,共 个;

总计 个。

样例说明 2

  • 长度为 的好串:97856,共 个;
  • 长度为 的好串:97788556,共 个;
  • 长度为 的好串:978785856,共 个;
  • 长度为 的好串:7856,共 个;

总计 个。

评测用例规模与约定

  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于 的评测用例,
  • 对于所有评测用例, 中只包含数字字符

解法

找规律

P12144 [蓝桥杯 2025 省 A] 地雷阵

题目描述

小蓝正在平面直角坐标系中的第一象限里玩一个逃生小游戏。在第一象限中埋有 颗地雷,第 颗地雷的坐标为 ,触发范围为以 为圆心,半径为 的圆。一旦小蓝走进了圆内就会触发地雷导致游戏失败。小蓝初始在原点 上,他需要在第一象限内选择一个方向一直往前走,如果能不触发任何地雷即可成功通关游戏。他想知道在 中均匀随机选择一个方向,即在 (朝向 轴正方向)至 (朝向 轴正方向)之间随机选择一个方向,通关游戏的概率是多少?

输入格式

输入的第一行包含一个正整数

接下来 行,每行包含三个正整数 ,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个实数,四舍五入保留三位小数,表示答案。

输入输出样例 #1

输入 #1

1
2
1
2 2 1

输出 #1

1
0.540

输入输出样例 #2

输入 #2

1
2
3
2
1 3 1
3 1 1

输出 #2

1
0.181

说明/提示

评测用例规模与约定

  • 对于 的评测用例,
  • 对于所有评测用例,

解法

根据圆形切线的性质,每一个圆都可以对应一个角度范围。对角度范围进行排序,就是一个线段覆盖的贪心问题。

碎碎念 注意反三角函数在C++里是atan,还有他是弧度还是角度?π 以及它的各个倍数在C++里也是有现成的值,好像是什么M_PI?我当时直接跑到文件夹里搜索的()而且应该是有弧度角度转换的函数吧

P12145 [蓝桥杯 2025 省 A] 扫地机器人

题目描述

在一个含有 个点 条边的无重边无自环的连通无向图中,有一个扫地机器人在执行清扫作业。其中结点 的标记 :如果为 ,则说明该结点需要进行清扫,扫地机器人在到达这个结点时会顺便进行清扫工作。机器人想知道,如果选定任意结点出发,每条边只能经过一次的话,最多能清扫多少个待清扫结点?

输入格式

输入的第一行包含一个正整数

第二行包含 个整数 ,相邻整数之间使用一个空格分隔。

接下来 行,每行包含两个正整数 ,用一个空格分隔,表示结点 和结点 之间有一条边。

输出格式

输出一行包含一个整数表示答案。

输入输出样例 #1

输入 #1

1
2
3
4
5
6
7
8
9
10
11
9
1 0 1 0 0 1 1 0 1
2 8
2 9
2 5
1 5
1 3
1 4
4 5
4 6
6 7

输出 #1

1
4

说明/提示

样例说明

其中一种可行路线:,清扫结点 (共 个)。

评测用例规模与约定

  • 对于 的评测用例,
  • 对于所有评测用例,

解法

一眼顶针,题目里的图为 个结点和 条边的连通图。当有 个结点和 条边的连通图,这是一颗树,树再加上一条边,就是只有一个环的图。除了一个环,剩下都是树的图,即基环树

题意:一个基环树,每个点的权值为0或1,选择一条链,点不能走重复,权值总和最大。

那么,我们的最佳路线,有可能有三种:

  1. 从叶子结点出发,到某一个祖先,再跑到另一个叶子结点
  2. 从叶子结点出发,走到环绕到另一个分岔路口,再走到另一个叶子结点;
  3. 同样从叶子结点出发,走到环跑一圈;或者根本没有叶子结点,直接跑一圈。
    基环树
    这时候可以从叶子结点开始拓补排序,得到从这个环结点进出环的点权值之和。
    考试的时候就只写完了拓补排序,还没有跑环就到时间了。最后一题也算了。

网上的教程,包括官方的教程不太适用,自己摸索了一遍

下载安装驱动

有两种芯片,看你的小芯片上写的是CP2102还是CH340G👀(两个小按键之间),选择不同的驱动。

CP2102芯片

CP2102驱动下载地址:
https://www.silabs.com/developer-tools/usb-to-uart-bridge-vcp-drivers?tab=downloads
选择CP210x Windows Drivers下载,解压。
图片
然后安装。
笔记本电脑选:CP210xVCPInstaller_x64.exe
台式电脑(诶?)选:CP210xVCPInstaller_x86.exe

CH340G芯片

驱动下载地址:
https://www.arduined.eu/ch340-windows-10-driver-download/
点击蓝字CH340 driver for Windows 10下载,解压。点SETUP.EXE安装。

Tips

如果你没有放大镜,看不清楚的话,你也可以两个都装,因为非常好装。

连接设备

长按Esp板子上的boot按键,同时插上电脑,并抬起按键。
同时按下组合键:“Win + R”,打开“运行”对话框,在其中输入“devmgmt.msc”,点击“确定”即可打开“设备管理器”。点开端口。应该能看到包含芯片名称的一个端口,如图
图片
如果没有的话,首先不要怀疑驱动,建议你先多换几个USB线,我换了三根三根。。。
然后记住是COM几,我的是COM4,下面的步骤记得替换。

下载固件

最新固件网址:
https://micropython.org/download/ESP8266_GENERIC/
直接找到
Firmware
Releases
初学者下载最上方的bin文件即可(带latest标识)。本人下载的时候版本是v1.24.1 (2024-11-29) .bin
图片

下载python

确保已安装Python 3.7或更高版本。虽然官网说, Python 2.7和Python 3.4以上都可以,但是你也不希望被同学知道你还在用老版本的Python吧(不是)。

Python官网:https://www.python.org/

用pip安装esptool

首先你有可能要更新pip。

1
python.exe -m pip install --upgrade pip

接着

1
pip install esptool

找到你Python的Scripts文件夹(里面应该有个esptool.exe),加上记住它的路径。再在后面加上esptool

找到esptool的一种方式
cmd怎么打开 win+R打开运行,输入cmd,回车

在cmd,或者Vscode bash或者Pycharm bash或者powershell或者别的里,输入

1
pip --version

我这里显示了

1
pip 25.0.1 from D:\GitHub\Smart-Aquaculture-esp8266\.venv\lib\site-packages\pip (python 3.10)

看到这个D:\GitHub\Smart-Aquaculture-esp8266\.venv\lib\site-packages\pip,去掉lib\site-packages\pip,换成Scripts\esptool,即D:\GitHub\Smart-Aquaculture-esp8266\.venv\Scripts\esptool。等会儿要用。

</details>

下面的.venv/Scripts/esptool替换成你的路径
因为我建了虚拟环境,就用相对路径了,所以后面就用.venv/Scripts/esptool简化写了。

对于以下两个命令,你需要更改三个地方:

  1. .venv/Scripts/esptool改成你在用pip安装esptool一步找到esptool的路径。
  2. COM4改成在连接设备一步找到的COM几
  3. D:\software\ESP8266_GENERIC-20241129-v1.24.1.bin改成你在下载固件一步下载的固件的路径。

打开cmd,先擦除闪存

1
.venv/Scripts/esptool --port COM4 erase_flash

然后烧录固件
1
.venv/Scripts/esptool --port COM4  --baud 460800 write_flash --flash_size=detect 0  D:\software\ESP8266_GENERIC-20241129-v1.24.1.bin

下载安装ide

推荐thonny。
下载地址:https://thonny.org/
虽然这个软件某不可言说的方面有点抽象,但是是确实好用。也可以选择别的ide。

如图:
图片

图片

Hello world!

成功打开之后,Ctrl+N新建main.py文件,到了喜闻乐见的Hello world环节

1
print("hello world!")

F5运行,看看能不能hello world。

Blink!

图片

参考网址:
https://docs.micropython.org/en/latest/esp8266/tutorial/intro.html

环境安装

CUDA

python

这里我装的是python3.9,因为装python3.7的话cuda似乎没有对应版本。新建一个miniconda环境。

pytorch

查找和cuda相对应的版本号,例如Cuda 12.8

1
pip install --pre torch torchvision  --index-url https://download.pytorch.org/whl/nightly/cu128

1
2
3
python font2img.py --src_font=src.otf --dst_font=trg.otf --charset=CN --sample_count=1000 --sample_dir=dir --label=0 --filter --shuffle --mode=font2font
python package.py --dir=dir --save_dir=experiment/data --split_ratio=0.8
python train.py --experiment_dir=experiment --gpu_ids=cuda:0 --batch_size=32 --epoch=100 --sample_steps=200 --checkpoint_steps=500

单调栈

模板

原题
题意:对于数列,中每一个数,输出这个数后面第一个大于它的下标
思路:栈内从大往小放,当栈顶的数小于当前数时,更新栈顶数的answer并弹出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <bits/stdc++.h>
using namespace std;
const int N = 3e6 + 5;
using ll = long long;
int n, p = 0;
int a[N], st[N], f[N];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
for (; p && a[st[p - 1]] < a[i]; --p)
{
f[st[p - 1]] = i;
}
st[p++] = i;
}
for (int i = 1; i <= n; i++)
cout << f[i] << ' ';
return 0;
}

经典题:接雨水

原题

一个单调递减的单调栈,能找到每个柱子左边和右边的第一个比它高的柱子,从而计算出可以接住的雨水量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def trap(self, height: List[int]) -> int:
st=[]
ans=0
for r,rh in enumerate(height):
while st and height[st[-1]]<rh:
bottom=st.pop()
if not st:
break
l=st[-1]
w=r-l-1
h=min(height[l],height[r])-height[bottom]
ans+=w*h
st.append(r)
return ans

滑动窗口/单调队列

模板

原题
题意:滑动窗口的最小值和最大值

思路:
有更好的新员工,立刻淘汰老员工;
老员工过期了,多好也要淘汰;
新员工永远来到队伍的最底端,队列从头到尾,是从又优秀又老的Top员工,到又普通又新的Back员工。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, k, a[N];
deque<int> maxq, minq;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n >> k;
for (int i = 0; i < n; i++)
cin >> a[i];
// 区间最小
for (int i = 0; i < k; i++)
{
while (!minq.empty() && minq.front() <= i - k)
minq.pop_front();
while (!minq.empty() && a[minq.back()] >= a[i])
minq.pop_back();
minq.push_back(i);
}
cout << a[minq.front()];
for (int i = k; i < n; i++)
{
while (!minq.empty() && minq.front() <= i - k)
minq.pop_front();
while (!minq.empty() && a[minq.back()] >= a[i])
minq.pop_back();
minq.push_back(i);
cout << ' ' << a[minq.front()];
}
cout << endl;

// 区间最大
for (int i = 0; i < k; i++)
{
while (!maxq.empty() && maxq.front() <= i - k)
maxq.pop_front();
while (!maxq.empty() && a[maxq.back()] <= a[i])
maxq.pop_back();
maxq.push_back(i);
}
cout << a[maxq.front()];
for (int i = k; i < n; i++)
{
while (!maxq.empty() && maxq.front() <= i - k)
maxq.pop_front();
while (!maxq.empty() && a[maxq.back()] <= a[i])
maxq.pop_back();
maxq.push_back(i);
cout << ' ' << a[maxq.front()];
}
cout << endl;
return 0;
}

经典题:无重复字符的最长子串

原题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
const set=new Set();
let j=0,ans=0,n=s.length;
for(i=0;i<n;i++){
while(j<n&&!set.has(s[j])){
set.add(s[j]);
j++;
}
ans=Math.max(ans,j-i);
set.delete(s[i]);
}
return ans;
};

https://leetcode.cn/problems/find-all-anagrams-in-a-string?envType=study-plan-v2&envId=top-100-liked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Solution {
public IList<int> FindAnagrams(string s, string p) {
var ans=new List<int>();
int sl=s.Length,pl=p.Length;
if(sl<pl){
return ans;
}
int[] cnt=new int[26];
int dif=0;
for(int i=0;i<pl;i++){
++cnt[s[i]-'a'];
--cnt[p[i]-'a'];
}
for(int i=0;i<26;i++){
if(cnt[i]!=0) ++dif;
}
if(dif==0) ans.Add(0);
for(int i=0;i<sl-pl;i++){
int idx=s[i]-'a';
if(cnt[idx]==1) --dif;
else if(cnt[idx]==0) ++dif;
--cnt[idx];

idx=s[i+pl]-'a';
if(cnt[idx]==-1) --dif;
else if(cnt[idx]==0) ++dif;
++cnt[idx];

if(dif==0) ans.Add(i+1);
}
return ans;
}
}

2023的题还需要烧烤一下/(ㄒoㄒ)/~~
所以先做2022的题
暂未完成:最长上升子序列


P8770 [蓝桥杯 2022 省 A] 填空问题

题目描述

试题 A :裁纸刀

【问题描述】

小蓝有一个裁纸刃,每次可以将一张纸沿一条直线裁成两半。

小蓝用一张纸打印出两行三列共 个二维码,至少使用九次裁出来,下图给出了一种裁法。

在上面的例子中,小蓝的打印机没办法打印到边缘,所以边缘至少要裁 次。另外,小蓝每次只能裁一张纸,不能重叠或者拼起来裁。

如果小蓝要用一张纸打印出 列共 个二维码,他至少需要裁多少次?

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

试题 B:灭鼠先锋

【问题描述】

灭鼠先锋是一个老少咸宜的棋盘小游戏,由两人参与,轮流操作。

灭鼠先锋的棋盘有各种规格,本题中游戏在两行四列的棋盘上进行。游戏的规则为:两人轮流操作,每次可选择在棋盘的一个空位上放置一个棋子,或在同一行的连续两个空位上各放置一个棋子,放下棋子后使棋盘放满的一方输掉游戏。

小蓝和小乔一起玩游戏,小蓝先手,小乔后手。小蓝可以放置棋子的方法很多,通过旋转和翻转可以对应如下四种情况:

1
2
X000 XX00 OXOO OXXO
0000 0000 0000 0000

其中 O 表示棋盘上的一个方格为空,X 表示该方格已经放置了棋子。

请问,对于以上四种情况,如果小蓝和小乔都是按照对自己最优的策略来玩游戏,小蓝是否能获胜。如果获胜,请用 V 表示,否则用 L 表示。请将四种情况的胜负结果按顺序连接在一起提交。

解法

裁纸刀

灭鼠先锋

博弈论

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits\stdc++.h>
using namespace std;
char board[5];
bool dfs()
{
if (strcmp(board, "XXXX") == 0)
{
return false;
}
for (int i = 0; i < 4; i++)
{
if (board[i] == 'O')
{
board[i] = 'X';
if (!dfs())
{
board[i] = 'O';
return true;
}
if (board[i + 1] == 'O')
{
board[i + 1] = 'X';
if (!dfs())
{
board[i] = 'O';
board[i + 1] = 'O';
return true;
}
board[i + 1] = 'O';
}
board[i] = 'O';
}
}
}
int main()
{
char con[][5] = {"XOOO", "XXOO", "OXOO", "OXXO"};
for (int i = 0; i < 4; i++)
{
strcpy(board, con[i]);
if (!dfs())//you fail
putchar('V');
else
putchar('L');
}
return 0;
}

[蓝桥杯 2022 省 A] 求和

题目描述

给定 个整数 , 求它们两两相乘再相加的和,即

输入格式

输入的第一行包含一个整数

第二行包含 个整数

输出格式

输出一个整数 ,表示所求的和。请使用合适的数据类型进行运算。

样例 #1

样例输入 #1

1
2
4
1 3 6 9

样例输出 #1

1
117

提示

对于 的数据,

对于所有评测用例,

蓝桥杯 2022 省赛 A 组 C 题。

解法

后缀和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<bits/stdc++.h>
using ll=unsigned long long;
const int N=(2e5)+5;
using namespace std;
int n;
int a[N];
ll sum=0;
ll ans=0;
int main() {
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(int i=n-1;i>=0;i--){
ans+=a[i]*sum;
sum+=a[i];
}
printf("%lld",ans);
return 0;
}


[蓝桥杯 2022 省 A] 选数异或

题目描述

给定一个长度为 的数列 和一个非负整数 , 给定 次查询, 每次询问能否从某个区间 中选择两个数使得他们的异或等于

输入格式

输入的第一行包含三个整数

第二行包含 个整数

接下来 行,每行包含两个整数 表示询问区间

输出格式

对于每个询问, 如果该区间内存在两个数的异或为 则输出 yes, 否则输出 no

样例 #1

样例输入 #1

1
2
3
4
5
6
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3

样例输出 #1

1
2
3
4
yes
no
yes
no

提示

【样例说明】

显然整个数列中只有 2,3 的异或为 1 。

【评测用例规模与约定】

对于 的评测用例, ;

对于 的评测用例, ;

对于所有评测用例,

蓝桥杯 2022 省赛 A 组 D 题。

解法

异或:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<bits/stdc++.h>
const int N=(1e5)+5;
using namespace std;
int n,m,x;
unordered_map<int,int> mp;//数值,对应位置
int f[N];//对于查询[l,r],f[r]表示[l,r]要有相配答案,l的最右
int main() {
scanf("%d%d%d",&n,&m,&x);
int a;
for(int i=1;i<=n;i++){
scanf("%d",&a);
f[i]=max(f[i-1],mp[a^x]);//找到达到要求的最左边界
mp[a]=i;
}
int l,r;
while(m--){
scanf("%d%d",&l,&r);
if(l<=f[r])
printf("yes\n");
else
printf("no\n");
}
return 0;
}


[蓝桥杯 2022 省 A] 爬树的甲壳虫

题目描述

有一只甲壳虫想要爬上一颗高度为 的树,它一开始位于树根, 高度为 ,当它尝试从高度 爬到高度为 的位置时有 的概率会掉回树根, 求它从树根爬到树顶时, 经过的时间的期望值是多少。

输入格式

输入第一行包含一个整数 表示树的高度。

接下来 行每行包含两个整数 , 用一个空格分隔,表示

输出格式

输出一行包含一个整数表示答案,答案是一个有理数,请输出答案对质数 取模的结果。其中有理数 对质数 取模的结果是整数 满足

样例 #1

样例输入 #1

1
2
1
1 2

样例输出 #1

1
2

样例 #2

样例输入 #2

1
2
3
4
3
1 2
3 5
7 11

样例输出 #2

1
623902744

提示

对于 的评测用例, ;

对于 的评测用例, ;

对于所有评测用例,

蓝桥杯 2022 省赛 A 组 E 题。

bgm🐌🎵

是🐞不是🐌喂

解法

状态转移

设从高度爬到高度的期望时间是.


转移方程:

费马小定理的一种表述:对于任意整数和质数,有

模运算和逆元

在模运算中,使用逆元将除法转换为乘法,避免了直接计算分数。
快速幂模板
乘法逆元模板

逆元的定义:如果存在一个整数 ,使得 ,那么 就是 在模 下的逆元

费马小定理的一种表述:如果是一个质数,且 互质,那么:
另一种表述:对于任意整数和质数,有

计算 在模下的值。根据费马小定理得到:

对于模数,它是一个质数,所以可以直接用 来计算

快速幂函数

函数quick_pow用于计算 。它利用了快速幂算法,时间复杂度为
通过不断将指数右移(相当于除以2),并根据当前指数的奇偶性决定是否将当前的乘到结果中。
将分数转换为模运算下的乘法。

总代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<bits/stdc++.h>
using ll=unsigned long long;
const int p=998244353;//取模
using namespace std;
int n;
ll x,y,f;
ll quick_pow(ll a){
ll res=1;
ll b=p-2;
while(b){
if(b&1){
res=res*a%p;
}
a=a*a%p;
b>>=1;
}
return res;
}
int main() {
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%lld%lld",&x,&y);
f=((f+1)*y%p)*quick_pow(y-x)%p;
}
cout<<f<<endl;
return 0;
}

时间复杂度
每次计算逆元的时间复杂度为
总时间复杂度为 ,其中 n 是树的高度。


[蓝桥杯 2022 省 A] 青蛙过河

题目描述

小青蛙住在一条河边,它想到河对岸的学校去学习。小青蛙打算经过河里的石头跳到对岸。

河里的石头排成了一条直线,小青蛙每次跳跃必须落在一块石头或者岸上。不过,每块石头有一个高度,每次小青蛙从一块石头起跳,这块石头的高度就会下降 ,当石头的高度下降到 时小青蛙不能再跳到这块石头上(某次跳跃后使石头高度下降到 是允许的)。

小青蛙一共需要去学校上 天课,所以它需要往返 次。当小青蛙具有一个跳跃能力 时,它能跳不超过 的距离。

请问小青蛙的跳跃能力至少是多少才能用这些石头上完 次课。

输入格式

输入的第一行包含两个整数 , 分别表示河的宽度和小青蛙需要去学校的天数。请注意 才是实际过河的次数。

第二行包含 个非负整数 , 其中 表示在河中与 小青蛙的家相距 的地方有一块高度为 的石头, 表示这个位置没有石头。

输出格式

输出一行, 包含一个整数, 表示小青蛙需要的最低跳跃能力。

样例 #1

样例输入 #1

1
2
5 1
1 0 1 0

样例输出 #1

1
4

提示

【样例解释】

由于只有两块高度为 的石头,所以往返只能各用一块。第 块石头和对岸的距离为 ,如果小青蛙的跳跃能力为 则无法满足要求。所以小青蛙最少需要 的跳跃能力。

【评测用例规模与约定】

对于 的评测用例,;

对于 的评测用例,;

对于所有评测用例,

蓝桥杯 2022 省赛 A 组 F 题。

bgm🐸🎵

解法

贪心+前缀和
对于每个起点,检查区间 内的石头总高度是否足够支持 次跳跃。
如果某个区间的石头总高度不足,则增加,扩大区间范围。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<bits/stdc++.h>
using namespace std;
using ll=unsigned long long;
const int N=(1e5)+5;
int n,x;//宽度和小青蛙需要去学校的天数。
ll sum[N];//石头总数前缀和
int main() {
scanf("%d%d",&n,&x);
x<<=1;//实际上让青蛙2x次过岸
int h;//石头高度
for(int i=1;i<n;i++)
{
scanf("%d",&h);
sum[i]=sum[i-1]+h;//[l,r]区间的石头总高度为sum[r]-sum[l-1]
}
int y=1;//跳跃能力
sum[n]=INT_MAX;//到对岸相当于有无数的石头
for(int i=0;i<n-y;i++)
while(sum[i+y]-sum[i]<x)//[i+1,i+y]区间不够2x只青蛙落脚
y++;
printf("%d",y);
return 0;
}

[蓝桥杯 2022 省 A] 最长不下降子序列

题目描述

给定一个长度为 的整数序列:。现在你有一次机会,将其中连续的 个数修改成任意一个相同值。请你计算如何修改可以使修改后的数列的最长不下降子序列最长,请输出这个最长的长度。

最长不下降子序列是指序列中的一个子序列,子序列中的每个数不小于在它之前的数。

输入格式

输入第一行包含两个整数

第二行包含 个整数

输出格式

输出一行包含一个整数表示答案。

样例 #1

样例输入 #1

1
2
5 1
1 4 2 8 5

样例输出 #1

1
4

提示

对于 的评测用例, ;

对于 的评测用例, ;

对于 的评测用例, ;

对于所有评测用例,

蓝桥杯 2022 省赛 A 组 G 题。

解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
```

---

# [蓝桥杯 2022 省 A] 扫描游戏

## 题目描述

有一根围绕原点 $O$ 顺时针旋转的棒 $OA$,初始时指向正上方(Y 轴正向)。平面中有若干物件,第 $i$ 个物件的坐标为 $\left(x_{i}, y_{i}\right)$,价值为 $z_{i}$。当棒扫到某个物件时,棒的长度会瞬间增长 $z_{i}$,且物件瞬间消失(棒的顶端恰好碰到物件也视为扫到),如果此时增长完的棒又额外碰到了其他物件,也按上述方式消去(它和上述那个点视为同时消失)。

如果将物件按照消失的时间排序,则每个物件有一个排名,同时消失的物件排名相同,请输出每个物件的排名,如果物件永远不会消失则输出 $-1$。

## 输入格式

输入第一行包含两个整数 $n$、$L$,用一个空格分隔,分别表示物件数量和棒的初始长度。

接下来 $n$ 行每行包含第三个整数 $x_{i}, y_{i}, z_{i}$。

注意存在 $(x_{i}, y_{i})=(0,0)$ 的情况,这些点视为一开始就立刻被碰到。

## 输出格式

输出一行包含 $n$ 整数,相邻两个整数间用一个空格分隔,依次表示每个物件的排名。

## 样例 #1

### 样例输入 #1

5 2
0 1 1
0 3 2
4 3 5
6 8 1
-51 -33 2

1
2
3

### 样例输出 #1


1 1 3 4 -1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

## 提示

对于 $30 \%$ 的评测用例,$1 \leq n \leq 500$ ;

对于 $60 \%$ 的评测用例,$1 \leq n \leq 5000$;

对于所有评测用例,$1 \leq n \leq 2\times10^5,-10^{9} \leq x_{i}, y_{i} \leq 10^{9}, 1 \leq L, z_{i} \leq 10^{9}$ 。

样蓝桥杯 2022 省赛 A 组 H 题。

## 题解

为什么不试试优先队列呢?
此处建议用斜率代替角度,角度每个网站的数据要求精度不一样。但我过了洛谷和蓝桥杯官网就懒得改了```(*ꈍ◡ꈍ*)```

```cpp
#include <bits/stdc++.h>
using ll = long long;
using ull = unsigned long long;
const int N = (2e5) + 5;
const double pi2 = 2 * M_PI; // 2*圆周率pi
using namespace std;

struct point {
int id; // 序号
int z; // 碰到增加的值
ull r; // 半径的平方
double angle; // 角度(以从y轴正方向开始的顺时针角度表示)
bool operator>(const point &other) const {
return angle > other.angle; // 优先队列按角度排序
}
} p[N];

int main() {
int n;//棒的个数
ull l;//棒的长度
__int128 l2;//棒的长度的平方,棒的长度的平方。__int128防止超过数据范围
scanf("%d%lld", &n, &l);
l2 = l * l;
ll x, y;
for (int i = 0; i < n; i++) {
scanf("%lld%lld%d", &x, &y, &p[i].z);
p[i].id = i;
p[i].r = x * x + y * y;//半径的平方
p[i].angle = atan2(x, y);//算角度。atan2可以处理为0的情况,注意是顺时针从y轴正方向开始
if (p[i].angle < 0)//把第二、三象限的角度转过来
p[i].angle = pi2 + p[i].angle;
}
sort(p, p + n, [](const point &a, const point &b) -> bool {
return a.r < b.r;
});//按半径排序
priority_queue<point, vector<point>, greater<>> q; // 按角度排序的优先队列
int pos;
for (pos = 0; pos < n && p[pos].r <= l2; pos++) {
q.push(p[pos]);
}

int cnt = 1, last_cnt = 1;//排名,并列排名
int ans[N];//答案
double rounds = pi2, angle = 0; // rounds 表示本轮结束的角度,angle 保存上一个被扫到的点的角度
memset(ans, -1, sizeof(ans));//初始化为-1
const double eps = 1e-11; // 浮点数比较阈值。1e-9官网过不了

while (!q.empty()) {
point u = q.top();
q.pop();
if (u.angle > rounds + eps) // 如果当前点的角度超过本轮结束的角度
rounds += pi2;
if (fabs(u.angle - angle) < eps) { // 判断两角度是否“相等”,用并列排名
ans[u.id] = last_cnt;
} else {
last_cnt=ans[u.id]=cnt;//更新并列的排名
angle=u.angle;//角度
}
++cnt;//更新排名

l += u.z;
l2 = l * l;
while (pos < n && p[pos].r <= l2) {
// 新点的角度转换到绝对角度,先加上当前轮次的偏移量
p[pos].angle += (rounds - pi2);
if (p[pos].angle < angle - eps) {
p[pos].angle += pi2;
}
q.push(p[pos]);
++pos;
}
}
printf("%d", ans[0]);
for (int i = 1; i < n; i++)
printf(" %d", ans[i]);
return 0;
}


[蓝桥杯 2022 省 A] 数的拆分

题目描述

给定 个正整数 ,分别问每个 能否表示为 的形式,其中 为正整数, 为大于等于 的正整数。

输入格式

输入第一行包含一个整数 表示询问次数。

接下来 行,每行包含一个正整数

输出格式

对于每次询问,如果 能够表示为题目描述的形式则输出 yes,否则输出 no

样例 #1

样例输入 #1

1
2
3
4
5
6
7
8
7
2
6
12
4
8
24
72

样例输出 #1

1
2
3
4
5
6
7
no
no
no
yes
yes
no
yes

提示

【样例说明】

个数分别可以表示为:

【评测用例规模与约定】

对于 的评测用例,;

对于 的评测用例,;

对于 的评测用例,;

对于所有评测用例,

蓝桥杯 2022 省赛 A 组 I 题。

解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<bits/stdc++.h>
using ll=long long;
const int N=4000;
using namespace std;
int n;
int not_prime[N+4];
vector<int> primes;
inline void init_primes(){
for(int i=2;i<=N;i++){
if(!not_prime[i]){
primes.push_back(i);
}
for(int j:primes){
if(i*j>N)
break;
not_prime[i*j]=true;
if(i%j==0)
break;
}
}
}
inline bool check(ll x){
ll y=pow(x,0.5);
if(y*y==x)
return true;
y=pow(x,1.0/3);
if(y*y*y==x||(y+1)*(y+1)*(y+1)==x)//?
return true;
return false;
}
int main() {
init_primes();
int t;
ll n;
scanf("%d",&t);
while(t--){
scanf("%lld",&n);
if(check(n)){
printf("yes\n");
continue;
}
bool flag=true;
for(int i:primes){
int cnt=0;
while(n%i==0){
n/=i;
cnt++;
}
if(cnt==1){
flag=false;
break;
}
}
if(flag&&check(n)){
printf("yes\n");
}
else{
printf("no\n");
}

}
return 0;
}

[蓝桥杯 2022 省 A] 推导部分和

题目描述

对于一个长度为 的整数数列 ,小蓝想知道下标 的部分和 是多少?

然而,小蓝并不知道数列中每个数的值是多少,他只知道它的 个部分和的值。其中第 个部分和是下标 的部分和 , 值是

输入格式

第一行包含 3 个整数 。分别代表数组长度、已知的部分和数量 和询问的部分和数量。

接下来 行,每行包含 个整数

接下来 行,每行包含 个整数 ,代表一个小蓝想知道的部分和。

输出格式

对于每个询问, 输出一行包含一个整数表示答案。如果答案无法确定, 输出 UNKNOWN

样例 #1

样例输入 #1

1
2
3
4
5
6
7
5 3 3
1 5 15
4 5 9
2 3 5
1 5
1 3
1 2

样例输出 #1

1
2
3
15
6
UNKNOWN

提示

对于 的评测用例,

对于 的评测用例,

对于 的评测用例,

对于 的评测用例,

对于 的评测用例,

对于所有评测用例, , 。数据保证没有矛盾。

蓝桥杯 2022 省赛 A 组 J 题。

解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include<bits/stdc++.h>

using namespace std;
using ll = long long;
vector<int> pa;
vector<ll> sum;

int find(int x) {
if (x != pa[x]) {
int root = find(pa[x]);
sum[x] += sum[pa[x]];
pa[x] = root;
}
return pa[x];
}

int main() {
int n, m, q;
scanf("%d%d%d", &n, &m, &q);

pa.resize(n + 1);
sum.resize(n + 1, 0);
iota(pa.begin(), pa.end(), 0);
int l, r;
ll s;
while (m--) {
scanf("%d%d%lld", &l, &r, &s);
int root_l = find(l - 1);
int root_r = find(r);
if (root_l != root_r) {
pa[root_r] = root_l;
sum[root_r] = s + sum[l - 1] - sum[r];
}
}
while (q--) {
scanf("%d%d", &l, &r);
if (find(l - 1) == find(r)) {
printf("%lld\n", sum[r] - sum[l - 1]);
} else {
printf("UNKNOWN\n");
}
}
return 0;
}

好几道题还没做。
算了,寒假里做几道放几道呗

[蓝桥杯 2023 省 A] 填空问题

题目描述

A. 幸运数

小蓝认为如果一个数含有偶数个数位,并且前面一半的数位之和等于后面一半的数位之和,则这个数是他的幸运数字。例如 是一个幸运数字,因为它有 个数位,并且 。现在请你帮他计算从 之间共有多少个不同的幸运数字。

B. 有奖问答

小蓝正在参与一个现场问答的节目。活动中一共有 道题目,每题只有答对和答错两种情况,每答对一题得 分,答错一题分数归零。

小蓝可以在任意时刻结束答题并获得目前分数对应的奖项,之后不能再答任何题目。最高奖项需要 分,所以到达 分时小蓝会直接停止答题。

已知小蓝最终实际获得了 分对应的奖项,请问小蓝所有可能的答题情况有多少种?

提示

第十四届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组 A-B

解法

填空题,暴!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
long long ans1,ans2;//4430091,8335366
// 11~99999999
void solve1(){
int cnt[40][5]={0};//和为几(1~36),几位数(1~4)
for(int i=1;i<=9999;i++){
int w=0,s=0,a=i;
while(a){
w++;
s+=a%10;
a/=10;
}
cnt[s][w]++;
}
for(int i=1;i<=36;i++){
for(int j=1;j<=4;j++){
int s=0;
for(int k=1;k<=j;k++){
s+=cnt[i][k];
}
ans1+=cnt[i][j]*s;
}
}
}
//答对,答错或者结束比赛
//300题拿了7分,答对1题加10分,答错分数归零。其中分数不可能>=100
void dfs(int t,int s){//题号,分数
if(s==100)//到达100分时小蓝会直接停止答题
return;
if(s==70){
ans2++;}
if(t==31)//比赛结束
return;
dfs(t+1,s+10);//答对+1
dfs(t+1,0);//答错分数归0
}
void solve2(){
dfs(1,0);
}


[蓝桥杯 2023 省 A] 平方差

题目描述

给定 ,问 中有多少个数 满足存在整数 使得

输入格式

输入一行包含两个整数 ,用一个空格分隔。

输出格式

输出一行包含一个整数满足题目给定条件的 的数量。

样例 #1

样例输入 #1

1
1 5

样例输出 #1

1
4

提示

【样例说明】

【评测用例规模与约定】

对于 的评测用例,

对于所有评测用例,

第十四届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组 C

解法

$$

1
2
3
4
5
6
7
8
9
#include <bits/stdc++.h>
using namespace std;
signed main()
{
int l, r;
cin >> l >> r;
cout << (r >> 1) + (r & 1) - (l >> 1) + (r >> 2) - (l >> 2) + !(l & 3) << endl;
return 0;
}


[蓝桥杯 2023 省 A] 更小的数

题目描述

image

小蓝有一个长度均为 且仅由数字字符 组成的字符串,下标从 ,你可以将其视作是一个具有 位的十进制数字 ,小蓝可以从 中选出一段连续的子串并将子串进行反转,最多反转一次。小蓝想要将选出的子串进行反转后再放入原位置处得到的新的数字 满足条件 ,请你帮他计算下一共有多少种不同的子串选择方案,只要两个子串在 中的位置不完全相同我们就视作是不同的方案。

注意,我们允许前导零的存在,即数字的最高位可以是 ,这是合法的。

输入格式

输入一行包含一个长度为 的字符串表示 (仅包含数字字符 ),从左至右下标依次为

输出格式

输出一行包含一个整数表示答案。

样例 #1

样例输入 #1

1
210102

样例输出 #1

1
8

提示

【样例说明】

一共有 种不同的方案:

  1. 所选择的子串下标为 ,反转后的
  2. 所选择的子串下标为 ,反转后的
  3. 所选择的子串下标为 ,反转后的
  4. 所选择的子串下标为 ,反转后的
  5. 所选择的子串下标为 ,反转后的
  6. 所选择的子串下标为 ,反转后的
  7. 所选择的子串下标为 ,反转后的
  8. 所选择的子串下标为 ,反转后的

【评测用例规模与约定】

对于 的评测用例,

对于 的评测用例,

对于所有评测用例,

解法

1
2
3
4
5
6
对于区间[l,r]
if l!=r:
if num[l]>num[r]:
可以翻转
elif [l+1,r-1]in [l,r] and [_l,_r]可以翻转:
可以翻转

动态规划,根据对称性,优化成一维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <bits/stdc++.h>
using namespace std;
#define N 5005
char num[N];
int n;
long long res;
bool f[N * 2];
signed main()
{
scanf("%s", num);
n = strlen(num);
for (register int k = 1; k < n; k++)
{
for (register int i = n - k - 1; i >= 0; i--)//正着也一样
{
int j = i + k;
if (num[i] > num[j])//可以翻转
{
res++;
f[i + j] = true;
}
else if (num[i] == num[j])//看区间[i+1,j-1]是否可以翻转
{
if (f[i + j])
res++;
}
else//不可以翻转
{
f[i+j]=false;
}
}
}
printf("%lld\n", res);
return 0;
}


[蓝桥杯 2023 省 A] 颜色平衡树

题目描述

给定一棵树,结点由 编号,其中结点 是树根。树的每个点有一个颜色

如果一棵树中存在的每种颜色的结点个数都相同,则我们称它是一棵颜色平衡树。

求出这棵树中有多少个子树是颜色平衡树。

输入格式

输入的第一行包含一个整数 ,表示树的结点数。

接下来 行,每行包含两个整数 ,用一个空格分隔,表示第 个结点的颜色和父亲结点编号。

特别地,输入数据保证 ,也即 号点没有父亲结点。保证输入数据是一棵树。

输出格式

输出一行包含一个整数表示答案。

样例 #1

样例输入 #1

1
2
3
4
5
6
7
6
2 0
2 1
1 2
3 3
3 4
1 4

样例输出 #1

1
4

提示

【样例说明】

编号为 个结点对应的子树为颜色平衡树。

【评测用例规模与约定】

对于 的评测用例,

对于 的评测用例,

对于所有评测用例,

解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
```

# [蓝桥杯 2023 省 A] 买瓜

## 题目描述

小蓝正在一个瓜摊上买瓜。瓜摊上共有 $n$ 个瓜,每个瓜的重量为 $A_i$。小蓝刀功了得,他可以把任何瓜劈成完全等重的两份,不过每个瓜只能劈一刀。

小蓝希望买到的瓜的重量的和恰好为 $m$。

请问小蓝至少要劈多少个瓜才能买到重量恰好为 $m$ 的瓜。如果无论怎样小蓝都无法得到总重恰好为 $m$ 的瓜,请输出 $-1$。

## 输入格式

输入的第一行包含两个整数 $n,m$,用一个空格分隔,分别表示瓜的个数和小蓝想买到的瓜的总重量。

第二行包含 $n$ 个整数 $A_i$,相邻整数之间使用一个空格分隔,分别表示每个瓜的重量。

## 输出格式

输出一行包含一个整数表示答案。

## 样例 #1

### 样例输入 #1

3 10
1 3 13

1
2
3

### 样例输出 #1


2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

## 提示

#### 【评测用例规模与约定】

对于 $20 \%$ 的评测用例,$n \leq 10$;

对于 $60 \%$ 的评测用例,$n \leq 20$;

对于所有评测用例,$1 \leq n \leq 30$,$1 \leq A_i \leq 10^9$,$1 \leq m \leq 10^9$。

## 前情提要🍉(bushi)

<iframe src="https://player.bilibili.com/player.html?aid=448136466&bvid=BV14j41117D6&cid=1259813341&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="position: absolute; width: 1000px; left: 0; top: 0;"> </iframe>

## 解法
(瞅了一眼标签,折半搜索?跟生瓜蛋子一样不熟)
西瓜对半切/不切,不妨乘二,当作一个西瓜/两个西瓜来做
先贪心排序,优先找大瓜。
然后深度优先搜索,根据质量上下超限(小于要求质量用后缀和判断)、劈瓜数已大于当前最小答案来剪枝。
```cpp
#include<bits/stdc++.h>
using ll=long long;
const int N=32;
using namespace std;
int n,mid,m;//西瓜总数量,一半数量,要求总质量
int ans=INT_MAX;//答案
int a[N];//有一个人前来买瓜
ll sum[N];//后缀和,用来剪枝
void dfs(int i,int num,int weight){//到哪个瓜了,劈了多少瓜,买了几斤瓜
if(weight>=m){
if(weight==m)
ans=min(ans,num);
return;
}
if(i==n||num>=ans||weight+sum[i]<m)//超总数的递归出口,超过最小劈瓜数递归,质量不足以达到要求数剪枝
return;
dfs(i+1,num,weight+(a[i]<<1));//卖你生瓜蛋子
dfs(i+1,num+1,weight+a[i]);//你**劈我瓜是吧!
dfs(i+1,num,weight);//你要不要吧
}
int main() {
scanf("%d%d",&n,&m);
mid=n/2;
m*=2;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(a,a+n,greater<>());//从大到小贪心
for(int i=n-1;i>=0;i--){
sum[i]=sum[i+1]+(a[i]<<1);//求后缀和
}
dfs(0,0,0);
if(ans==INT_MAX)
ans=-1;
printf("%d\n",ans);
return 0;
}


[蓝桥杯 2023 省 A] 网络稳定性

题目描述

有一个局域网,由 个设备和 条物理连接组成,第 条连接的稳定性为

对于从设备 到设备 的一条经过了若干个物理连接的路径,我们记这条路径的稳定性为其经过所有连接中稳定性最低的那个。

我们记设备 到设备 之间通信的稳定性为 的所有可行路径的稳定性中最高的那一条。

给定局域网中的设备的物理连接情况,求出若干组设备 之间的通信稳定性。如果两台设备之间不存在任何路径,请输出

输入格式

输入的第一行包含三个整数 ,分别表示设备数、物理连接数和询问数。

接下来 行,每行包含三个整数 ,分别表示 之间有一条稳定性为 的物理连接。

接下来 行,每行包含两个整数 ,表示查询 之间的通信稳定性。

输出格式

输出 行,每行包含一个整数依次表示每个询问的答案。

样例 #1

样例输入 #1

1
2
3
4
5
6
7
8
5 4 3
1 2 5
2 3 6
3 4 1
1 4 3
1 5
2 4
1 3

样例输出 #1

1
2
3
-1
3
5

提示

【评测用例规模与约定】

对于 的评测用例,

对于 的评测用例,

对于所有评测用例,

解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
```

---

# [蓝桥杯 2023 省 A] 异或和之和

## 题目描述

给定一个数组 $A_i$,分别求其每个子段的异或和,并求出它们的和。或者说,对于每组满足 $1 \leq L \leq R \leq n$ 的 $L,R$,求出数组中第 $L$ 至第 $R$ 个元素的异或和。然后输出每组 $L,R$ 得到的结果加起来的值。

## 输入格式

输入的第一行包含一个整数 $n$ 。

第二行包含 $n$ 个整数 $A_i$,相邻整数之间使用一个空格分隔。

## 输出格式

输出一行包含一个整数表示答案。

## 样例 #1

### 样例输入 #1

5
1 2 3 4 5

1
2
3

### 样例输出 #1


39
```

提示

【评测用例规模与约定】

对于 的评测用例,

对于 的评测用例,;

对于所有评测用例,

解法

异或的性质


(没什么,复习一下)

设序列为,从的异或和为, 从的异或前缀和为,则

即对~个前缀和,两两异或的和。
按二进制位数相加
```cpp

include

using namespace std;
using ll=long long;
const int N=(1e5)+5;
int n;
int f[N];
ll res=0ll;
int main() {
int a;
scanf(“%d”,&n);
for(int i=1;i<=n;i++){
scanf(“%d”,&a);
f[i]=f[i-1]^a;
}
int bei=1;//位权
for(int i=0;i<=20;i++){//20位二进制
int numof1=0,numof0=1;
ll sum=0;
for(int j=1;j<=n;j++){
if(f[j]&1){//最低一位1^0=1
sum+=numof0;
numof1++;
}else{//最低一位0^1=1
sum+=numof1;
numof0++;
}
f[j]>>=1;//下一位
}
res+=sum*bei;
bei<<=1;//位权翻倍
}
cout<<res<<endl;
return 0;
}
```..

0%