蓝桥杯Web2022年第十三届蓝桥杯Web大学组国赛真题解析
Posted 海底烧烤店ai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯Web2022年第十三届蓝桥杯Web大学组国赛真题解析相关的知识,希望对你有一定的参考价值。
前言
省赛真题解析见:
2022年第十三届蓝桥杯Web大学组省赛真题解析(完整版)
2022年第十三届蓝桥杯Web大学组省赛真题解析(精华版)
更多蓝桥杯题解请查阅专栏:蓝桥杯
之前写省赛解析时篇幅过长,写的花里胡哨的,导致文章阅读体验不好,这次就不整那些了,直接贴代码,解析都写在代码注释里了,相信各位老大稍微思考一下就能够理解了,同样的,相应的真题代码
也会分享给大家:
「蓝桥杯」https://www.aliyundrive.com/s/7fsobhSy8dZ 提取码: 34pi
如果在阅读文章时大佬有好的见解,或者发现了问题,还请多多留言,互相探讨
文章目录
1、分一分(5分)
/**
* @param Object oldArr
* @param Object num
* */
const splitArray = (oldArr, num) =>
// TODO:请补充代码实现功能
let newArr = [];
// 升序排序后解构赋值深拷贝给oldArr2
let oldArr2 = [...oldArr.sort((a, b) => a - b)];
const len = oldArr2.length;
for (let i = 0, j = 0; i < len; i += num, j++)
// splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
newArr[j] = oldArr2.splice(0, num);
return newArr;
;
module.exports = splitArray; // 检测需要,请勿删除
2、新鲜的蔬菜(5 分)
/* TODO:待补充代码 */
#box1
display: flex;
justify-content: center;
align-items: center;
#box2,
#box3
display: flex;
flex-direction: column;
justify-content: space-between;
#box2 span:nth-child(2),
#box3 span:nth-child(3)
align-self: flex-end;
#box3 span:nth-child(2)
align-self: center;
3、水果消消乐(10分)
// TODO:请补充代码
function startGame()
$("img").show(500);
$("#start").hide();
$("img").hide(500);
// 已经点击的数量
let i = 0;
// 存放已经点击的元素
let clickImg = [];
[...$(".img-box")].forEach((item) =>
item.onclick = function ()
i++;
if (i <= 2)
$(item.children).show();
clickImg.push(item);
if (i === 2)
setTimeout(() =>
let score = $("#score")[0];
if (
clickImg[0].children[0].alt ===
clickImg[1].children[0].alt
)
score.innerhtml = Number(score.innerHTML) + 2;
$(clickImg[0]).css(
// 隐藏元素且保留元素所占位置
visibility: "hidden",
);
$(clickImg[1]).css(
visibility: "hidden",
);
else
score.innerHTML = Number(score.innerHTML) - 2;
$(clickImg[0].children[0]).hide();
$(clickImg[1].children[0]).hide();
clickImg = [];
i = 0;
, 400);
;
);
4、用什么来做计算A (10分)
// TODO:请补充代码
const btn = document.getElementsByClassName("calc-button");
const formula = document.getElementById("formula");
const result = document.getElementById("result");
// 计算机表达式展示
let showText = "";
// 计算结果
let num = "";
[...btn].forEach((item) =>
item.onclick = function ()
switch (this.id)
// 点击 =
case "equal":
// eval() 函数会将传入的字符串当做 javascript 代码进行执行。
num = eval(showText.replace("x", "*").replace("÷", "/"));
result.value = num;
return;
// 点击 √
case "sqrt":
num = eval(showText.replace("x", "*").replace("÷", "/"));
num = Math.sqrt(num);
result.value = num;
return;
// 点击 AC
case "reset":
showText = "";
num = "";
formula.value = showText;
result.value = num;
return;
default:
showText += this.innerHTML;
formula.value = showText;
return;
;
);
5、开学礼物大放送(15 分)
考察的只是简答的页面实现,每个人的实现方式不同,代码差异也很大,这里就不放代码了
6、权限管理(15 分)
$(function ()
// 使用 ajax 获取 userList.json 数据并渲染到页面
getData();
// 为按钮添加事件
$("#add").click(function ()
// TODO:补充代码,实现功能
// 获取选中的option
let option = $("#leftSelect option:selected");
// jQ方法:each() 遍历jQ获取的节点
option.each((index, item) =>
// 删除左侧对应的option
$(`#leftSelect option[value=$item.value]`).remove();
// 向右侧添加option
$("#rightSelect")[0].add(new Option(item.value, item.value));
);
changeAccess("管理员", option);
);
$("#addAll").click(function ()
// TODO:补充代码,实现功能
let option = $("#leftSelect option");
option.each((index, item) =>
$(`#leftSelect option[value=$item.value]`).remove();
$("#rightSelect")[0].add(new Option(item.value, item.value));
);
changeAccess("管理员", option);
);
$("#remove").click(function ()
// TODO:补充代码,实现功能
let option = $("#rightSelect option:selected");
option.each((index, item) =>
$(`#rightSelect option[value=$item.value]`).remove();
$("#leftSelect")[0].add(new Option(item.value, item.value));
);
changeAccess("普通用户", option);
);
$("#removeAll").click(function ()
// TODO:补充代码,实现功能
let option = $("#rightSelect option");
option.each((index, item) =>
$(`#rightSelect option[value=$item.value]`).remove();
$("#leftSelect")[0].add(new Option(item.value, item.value));
);
changeAccess("普通用户", option);
);
);
/**
* 修改权限
* @param Object right 要修改的权限
* @param Object changeList 要修改权限的用户列表
*/
function changeAccess(right, changeList)
// TODO:补充代码,实现功能
changeList.each((index, item) =>
// 将option.value与tr.name对应,找到对应的td并修改其内容
// jQ方法::last 获取最后个元素
$(`#userList tr[name=$item.value] td:last`).html(right);
);
// 异步获取数据
function getData()
// TODO:补充代码,实现功能
$.ajax("./js/userList.json").then((res) =>
res.forEach((item) =>
// jQ方法:html() 设置html内容
$("#userList tbody").html(
$("#userList tbody").html() +
` <tr name=$item.name>
<td>$item.name</td>
<td>$item.right ? "管理员" : "普通用户"</td>
</tr>`
);
);
);
7、一起会议吧(20分)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>一起会议吧</title>
<link rel="stylesheet" type="text/css" href="./css/index.css" />
<link rel="stylesheet" href="./css/iconfont/iconfont.css" />
</head>
<body>
<div id="app">
<!-- TODO:请在下面实现需求 -->
<!-- 登录/注销窗口 -->
<div class="login">
<div class="left-tools">
<a class="close-btn"></a>
<a class="shrink-btn"></a>
</div>
<h3>isLogin?'注销':'登录'</h3>
<p v-if="!isLogin">
选择用户:<select id="selectUser" @change="changeOption($event)">
<option :value="item.id" v-for="item in list" :key="item.id">item.name</option>
</select>
</p>
<p v-else>当前用户为:loginUser.name</p>
<a class="login-btn" @click="btn">isLogin?'注销':'登录'</a>
</div>
<!-- 右侧显示用户列表窗口按钮 -->
<button id="show" class="right-btn" v-if="!showUser&&isLogin" @click="showUser=true">
<span class="iconfont icon-left-arrow"></span>
</button>
<!-- 用户列表窗口 -->
<div class="user-dialog" v-if="isLogin&&showUser">
<!-- 用户列表窗口上侧工具栏 -->
<ul class="tools">
<li class="tools-left">
<button :class="'active':isButton<0" @click="isButton=-1">
<span class="iconfont icon-close"></span>
</button>
<button :class="'active':isButton=='0'" @click="isButton=0">
<span class="iconfont icon-dialog"></span>
</button>
<button :class="'active':isButton>0" @click="isButton=1">
<span class="iconfont icon-list"></span>
</button>
</li>
<li class="tools-right">
<button class="show-list" @click="showUser=false">
<span class="iconfont icon-retract"></span>
</button>
</li>
</ul>
<!-- 用户列表 -->
<ul class="say-list">
<li>
<span class="iconfont icon-microphone"></span>
</li>
<li class="line"></li>
<li>正在讲话:list.find(item=>item.isHost).name;</li>
</ul>
<ul class="user-list">
<li v-show="isButton>=0">
<img class="header" :src="loginUser.imgPath" />
<div class="user-name">
<span class="iconfont icon-user header-icon" v-if="loginUser.isHost">第1题 —— 九进制转十进制 (5分)第2题 —— 顺子日期 (5分) 第3题 —— 刷题统计 (10分) 第4题 —— 修剪灌木 (10分) 第5题 —— X进制减法 (15分) 第6题 —— 统计子矩阵 (15分) 第7题 —— 积木画 (20分) 第8题 —— 扫雷 (20分) 第9题 —— 李白打酒加强版 (25分) 第10题 —— 砍竹子 (25分)
补题链接:地址
第1题 —— 九进制转十进制 (5分)
- 进制转换,9的0次方乘2+9的1次方乘2+2次方乘0+三次方乘9,输出就行。
- 答案:1478
#include <iostream>
using namespace std;
int main()
cout<<2+2*9+2*9*9*9<<"\\n";
return 0;
第2题 —— 顺子日期 (5分)
- 年份确定了是2022,可以枚举出每一天,然后暴力判断一下就行。
- 答案:14
#include<bits/stdc++.h>
using namespace std;
int days[13] = 0,31,28,31,30,31,30,31,31,30,31,30,31 ; //2022不是闰年
int main()
int cnt = 0;
for(int month = 1; month <= 12; month++)
for (int day = 1; day <= days[month]; day++)
string s = "2022";
if (month < 10) s += '0'+ to_string(month);
else s += to_string(month);
if (day < 10) s += '0' + to_string(day);
else s += to_string(day);
if(s.find("012") != s.npos || s.find("123") != s.npos)
cnt++;
cout<<cnt<<"\\n";
return 0;
第3题 —— 刷题统计 (10分)
- 不难想到暴力模拟,day++表示天数,然后不断减掉对应星期几的天数即可。
- 1e18会超时,因为每周的题数是固定的,所以单独拿出来做除法。
- 1e18要开longlong。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL; //开ll
int main()
LL a, b, n; cin>>a>>b>>n;
LL c = a*5+b*2; //每周做的题数
LL day = n/c*7; //直接除
n = n%c;
while(n > 0)
day++;
if(day%7==6 || day%7==0)n -= b; //周末
else n -= a;
cout<<day<<"\\n";
return 0;
第4题 —— 修剪灌木 (10分)
- 题意:给一个数组,每秒钟所有数+1,指针开始在最左边,每秒往右移动一个,到边界后转向回来然后往复循环,求数组可能产生的最大值。
- 其实一眼结论题
每个灌木被剪掉以后,在下一次被剪之前,这段时间内,灌木丛会生长到最大,就是看他什么下次什么时候被剪。
所以当前灌木丛的最大长度取决于灌木丛到两端点的距离,那么for一遍输出就行了。
#include<bits/stdc++.h>
using namespace std;
int main()
int n; cin>>n;
for(int i = 1; i <= n; i++)cout<<max(i-1,n-i)*2<<endl;
return 0;
第5题 —— X进制减法 (15分)
-
题意:定义X进制表示每一位进制不同的数。给出两个X进制数A和B(规则相同,但是不知道规则,且最高N进制,最低2进制),求A-B的可能最小值。
-
思路:
因为AB的规则是一样的,所以A-B第i位的值其实已经确定了,就是给他们加个规则。
那必然是进制越小越好,最好是2进制。
如果都是2进制就不满足规则了,所以最小进制肯定是右边i+1上A和B的最大+1,不要再大了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1000000007, maxn = 1e5+10;
LL a[maxn], b[maxn];
int main()
int n, an, bn; cin>>n>>an;
for(int i = an; i >= 1; i--)cin>>a[i];//1-n低位到高位
cin>>bn;
for(int i = bn; i >= 1; i--)cin>>b[i];
LL ans = 0, base = 1;
for(int i = 1; i <= an; i++)
LL w = max(a[i], b[i],1LL)+1;
ans = (ans+(a[i]-b[i])*base)%mod;
base = base*w%mod;
cout<<ans<<"\\n";
return 0;
第6题 —— 统计子矩阵 (15分)
- 题意:求给出的nm的矩阵里有多少个子矩阵满足和不超过k。
- 不难想到二维前缀和,然后暴力枚举对角线,四次方可以求出所有的解。
但是数据范围是500的,所以还要再优化一维。 - 不难想到枚举一个横坐标上的区间以后,纵坐标维度上的可以采用双指针(尺取法)来做。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 550;
LL a[maxn][maxn], b[maxn][maxn], ans;
int main()
int n, m, k; cin>>n>>m>>k;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin>>a[i][j];
a[i][j] += a[i-1][j]+a[i][j-1]-a[i-1][j-1];//二维前缀和
for(int l = 1; l <= m; l++)
for(int r = l; r <= m; r++)
for(int i = 1, j = 1; i <= n; i++) //双指针
while(j <= i && (a[i][r]-a[i][l-1]-a[j-1][r]+a[j-1][l-1])>k)
j++;
if(j <= i)ans += i-j+1;
cout<<ans<<"\\n";
return 0;
第7题 —— 积木画 (20分)
- 题意:有2种积木,2xn的板子,求有多少放法。
- 明显是个dp,想一下状态,令f(i,j) 表示前i-1列填满且第i列的状态为j,j=0(00) j=1(10) j=2(01) j=3(11)时候的放法数量。线性+2维的复杂度也是刚刚好。
- 然后转移的时候尝试把各种格子放进去即可。
- 这题一个比较坑的点是直接开longlong会爆内存,要int然后转longlong,内存卡的有点紧。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e7+10, mod = 1e9+7;
int f[maxn][4];
int main()
int n; cin>>n;
f[0][3] = 1;
f[1][0] = 1; f[1][1] = 1; f[1][2] = 1; f[1][3] = 2;
for(int i = 2; i <= n; i++)
f[i][0]=(LL)(f[i-1][3])%mod;
f[i][1]=(LL)(f[i-1][0]+f[i-1][2])%mod;
f[i][2]=(LL)(f[i-1][1]+f[i-1][0])%mod;
f[i][3]=((LL)(f[i-1][1]+f[i-1][2])%mod+(LL)(f[i-1][3]+f[i-2][3])%mod)%mod;
cout<<f[n][0]<<endl;
return 0;
第8题 —— 扫雷 (20分)
- 题意:给出n个地雷,坐标x,y和半径r的圆。接下来m个排雷火箭,也是坐标x,y和半径r的圆。排雷火箭范围内的地雷会爆炸,然后爆炸的地雷范围内的地雷也会爆炸,求最后炸了多少个地雷。
- 注意到所有点爆炸半径都不超过10,而且每个点坐标都是整数,那么对于一个点其半径内的点完全可以枚举出来,最多也就400个点,n是5e4,乘起来相当于遍历一遍所有可能的点,复杂度也够。
- 坐标直接用map存的话带个log会超时,所以要用无向的map(加个哈希)
#include<bits/stdc++.h>
using namespace std;
inline long long qpow(long long x) return x * x;
struct hsh
size_t operator () (const pair<int,int> &a) const
return a.first * 239 + a.second * 7;
;
unordered_map< pair<int,int>, int, hsh> mp;
unordered_map< pair<int,int>, int, hsh> rr;
long long ans = 0;
void dfs(int x, int y, int r)
for(int i = x-r; i <= x+r; i++) //枚举半径范围内的所有点
for(int j = y-r; j <= y+r; j++)
if(qpow(i-x)+qpow(j-y) <= qpow(r))
auto it = make_pair(i,j);
if(mp.count(it)) //判断是不是雷
ans += mp[it];
mp.erase(it);
dfs(i,j,rr[it]); //递归爆炸
int main()
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m; cin>>n>>m;
for(int i = 1; i <= n; i++)
int x, y, r; cin>>x>>y>>r;
auto pos = make_pair(x,y);
mp[pos]++;
rr[pos] = max(r, rr[pos]);
while(m--)
int x, y, r;
cin>>x>>y>>r;
dfs(x, y, r); //从这里开始爆炸
cout<<ans<<"\\n";
return 0;
第9题 —— 李白打酒加强版 (25分)
- 题意:开始有2斗酒, 逢店加一倍, 遇花喝一斗。一共遇到店 N 次, 遇到花 M 次。已知最后一次遇到的是花, 他正好把酒喝光了。求一路遇到店和花的顺序, 有多少种不同的可能?
没酒 ( 0 斗) 时遇店是合法的, 加倍后还是没酒; 但是没酒时遇 花是不合法的。 - 明显也是dp,比积木还简单一点,据说是有原题。令 f[i][j][k] 表示走过了 i 个酒馆,j 个花,还有 k 斗酒的方案数, 此时复杂度刚刚好。
- 转移:到酒馆时,因为到酒馆时翻一倍,所以这时的 k 一定是偶数。遇到花时,上一次的酒比当前多 1,所以从k+1转移。
- 可以用记忆化写,看起来清楚一点。
#include<bits/stdc++.h>
using namespace std;
int n, m,dp[110][110][110];
int dfs(int i, int j, int k)//走过了i个酒馆,j个花,还有k斗酒的方案数
if(i<0 || j<0 || k<0)return 0;//遇花,遇店,酒壶里的酒都要>=0
if(i>k)return 0; //每次要喝1,所以酒馆要小于总酒量
if(j==0 && i==1 && k==1)return 1; //边界状态,一个酒馆
if(dp[i][j][k] != -1)return dp[i][j][k];
return dp[i][j][k] = (dfs(2*i,j-1,k)+dfs(i-1,j,k-1))%1000000007;
int main()
memset(dp, -1, sizeof(dp));
cin>>n>>m;
cout<<dfs(2,n,m)<<"\\n";
return 0;
第10题 —— 砍竹子 (25分)
- 题意:一排n个竹子,每次可以选一个高度相等的区间变成根号hi/2+1下取整,求最少多少次能让所有竹子的高度变为1。
- 数据范围 2e5,暴力肯定过不去,估计nlogn。因为是根号,所以把一根竹子变成1最多只要操作6次,所以到时候肯定会有很多相等的区间的竹子,我们不妨贪心的从高到低砍竹子(这样肯定不会更坏)。
- 此时不难想到用堆维护,我们每次找出最高的竹子,把相同高度且编号连续的竹子依次取出(所以要重载结构体维护一个编号),然后把竹子砍一半再加入堆中。直到最高的竹子的高度是1就代表我们已经结束了。
- 用longlong的时候,sqrt要换成sqrtl!!不然会爆精度,其他类似的函数也是。
总结2点:
1、首先我们注意到,一般的做题过程就是,找到某个结论(关键点,突破口),然后做优化的那种题目,比如说数据范围1e5,但是某个数据很小(发现6次就砍完,地雷范围r<10),就可以拿这个做文章,再比如一眼暴力,然后想想怎么用结论(比如说来回走动的规律,到两边的距离,双指针)这种来优化,或者说其实大多数dp类型的思维/暴力题,都有点这种意味在里面。
2、另外一个思维的切入点是,先想清楚再写代码,think twice, code once,这样不容易思路被带偏,不要上来就啪啪啪输入输出,这样后面就卡住了(起码我是这样的,会被打断,可能题意都忘记了,那还写个锤子),大体思路想好,感觉方案可行了,优化完了再写,细节具体再补充上去就行,不要上来就暴力,不是每道题都有写暴力对拍的时间成本的。 虽然在写不出来了的时候多交一个暴力骗分也是一个好习惯。
#include<bits/stdc++.h>
using namespace std;
typedef 2022年第十三届蓝桥杯web开发—东奥大抽奖题目附官方解答
2022年第十三届蓝桥杯比赛Java B组 全部真题答案解析-第一部分