2025年睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛)解题报告 | 珂学家

2025年睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛)解题报告 | 珂学家

前言

在这里插入图片描述

题解

2025年睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛)解题报告

睿抗一如既往的码量大,喜欢阅读理解挖坑,T_T。

T3 应该是最简单,如果去掉匹配串 2 字节的限制,感觉会是一道有趣的题。

在这里插入图片描述

RC-u1 谁拿冠军了?

分值: 15分

考察点:hash表的使用

注意点:明明某一天里,可能存在多个相同操作,需要求其总和,在除 2。

#include<bits/stdc++.h>usingnamespace std;intmain(){int n, m; cin >> n >> m;int A1, A2, B1, B2, B3; cin >> A1 >> A2 >> B1 >> B2 >> B3;// 利用 array<int, 2> 表示二元组 (d,op) map<array<int,2>,int> ops;for(int i =0; i < n; i++){int d, op; cin >> d >> op; ops[{d, op}]+=1;}// 题意保证 一天最多一个操作 map<int,int> ban;for(int i =0; i < m; i++){int t, op; cin >> t >> op; ban[t]= op;}int sw1 =0, sw2 =0;for(auto[k, cnt]: ops){auto[d, op]= k;// 减半影响的操作if(ban.count(d)&& ban[d]== op){if(op ==1){ sw1 += A1 * cnt; sw2 -= B1 * cnt /2;}elseif(op ==2){ sw2 -= B2 * cnt /2;}elseif(op ==3){ sw1 -= A2 * cnt; sw2 -= B3 * cnt /2;}}else{if(op ==1){ sw1 += A1 * cnt; sw2 -= B1 * cnt;}elseif(op ==2){ sw2 -= B2 * cnt;}elseif(op ==3){ sw1 -= A2 * cnt; sw2 -= B3 * cnt;}}} cout << sw1 <<" "<< sw2 <<"\n";return0;}

RC-u2 理包

分值: 20分

思路:模拟

枚举包裹的空坐标,然后以物品坐标系,以相对偏移向量尝试填充匹配

感觉码量有点大,看起来简单,但写起来稍头痛。

#include<bits/stdc++.h>usingnamespace std;intmain(){int n, m, q; cin >> n >> m >> q; vector<string>g(n);for(int i =0; i < n; i++){ g[i].resize(m,'.');}while(q-->0){int r, c; cin >> r >> c; vector<string>mat(r);int sy =-1, sx =-1;for(int i =0; i < r; i++){ cin >> mat[i];if(sy ==-1){for(int j =0; j < c; j++){if(mat[i][j]=='*'){ sy = i; sx = j;break;}}}}// 以物品坐标去匹配包裹,oy/ox是相对偏移向量auto check =[&](int oy,int ox)->bool{for(int i =0; i < r; i++){for(int j =0; j < c; j++){if(mat[i][j]=='*'){if(i + oy >=0&& i + oy < n && j + ox >=0&& j + ox < m){if(g[i + oy][j + ox]=='*'){returnfalse;}}else{returnfalse;}}}}returntrue;};// 以物品坐标去填充包裹,oy/ox是相对偏移向量auto fill =[&](int oy,int ox){for(int i =0; i < r; i++){for(int j =0; j < c; j++){if(mat[i][j]=='*'){ g[i + oy][j + ox]='*';}}}};// 从包裹坐标出发,寻找空格去,查询是否放入物品 auto solve =[&](int&ay,int&ax)->bool{for(int i =0; i < n; i++){for(int j =0; j < m; j++){if(g[i][j]=='.'){if(check(i - sy, j - sx)){ ay = i; ax = j;fill(i - sy, j - sx);returntrue;}}}}returnfalse;};int ay =0, ax =0;if(solve(ay, ax)){ cout <<(ay +1)<<" "<<(ax +1)<<"\n";}else{ cout <<-1<<" "<<-1<<"\n";}}return0;}

RC-u3 删除屏蔽词

分值: 25分

思路:模拟+栈

这题限定模式串固定为2,如果为k,那这题就麻烦了。

就是当前字符,以及栈顶元素,是否构成模式串

注意: 需要输出 删除次数,不是最后文本的长度

#include<bits/stdc++.h>usingnamespace std;intmain(){ string p; string s;getline(cin, p);getline(cin, s);int del =0; stack<char> stk;for(char c: s){// 核心代码,就是这一行if(c == p[1]&&!stk.empty()&& stk.top()== p[0]){ stk.pop(); del++;}else{ stk.push(c);}} string buf;while(!stk.empty()){ buf.push_back(stk.top()); stk.pop();}reverse(buf.begin(), buf.end()); cout << del <<" "<< buf <<"\n";return0;}

RC-u4 穷游

分值: 30分

思路:二分 + dijkstra

可以先确定最小的住宿费用,再求解此基础上的最小时长。

这个套路,在睿抗编程赛中,多次出现。

二分check的核心逻辑是连通性,为了简化代码,可以复用带限制的求时长dijkstra

这样在追求编码效率 和 代码 AC 之间达到一个好的平衡。

#include<bits/stdc++.h>usingnamespace std;structE{int v, w;E(){}E(int v,int w):v(v),w(w){}};structP{int u, c;P(){}P(int u,int c):u(u),c(c){}};intmain(){int n, m; cin >> n >> m; vector<int>prices(n);for(int&x: prices) cin >> x; vector<vector<E>>g(n);for(int i =0; i < m; i++){int u, v, w; cin >> u >> v >> w; u--; v--; g[u].push_back(E(v, w)); g[v].push_back(E(u, w));}int s, e; cin >> s >> e; s--; e--;auto comp =[](const P&lhs,const P&rhs){return lhs.c > rhs.c;};int inf =0x3f3f3f3f;auto dijkstra =[&](int limit){ vector<int>dp(n, inf); dp[s]=0; priority_queue<P, vector<P>,decltype(comp)>pq(comp); pq.push(P(s,0));while(!pq.empty()){ P p = pq.top(); pq.pop();if(p.c > dp[p.u])continue;// 提前返回if(p.u == e){return p.c;}for(E &e: g[p.u]){if(prices[e.v]> limit)continue;if(dp[e.v]> p.c + e.w){ dp[e.v]= p.c + e.w; pq.push(P(e.v, dp[e.v]));}}}return inf;};int l =0, r =*max_element(prices.begin(), prices.end());// 二分确认最小费用while(l <= r){int mid = l +(r - l)/2;int ret =dijkstra(mid);if(ret != inf){ r = mid -1;}else{ l = mid +1;}}// 再求解最小时长int ret =dijkstra(l); cout << l <<" "<< ret <<"\n";return0;}

RC-u5 工序优化

分值: 30

思路: 动态规划

题目可以归纳如下,更好的理解

定义一个merge操作

  • 第i项可以和第i-1项合并,时间合并,工作时间按第i-1项为准,但需额外消耗 CiC_iCi​
  • 合并可以连续,即 [ia, b]的连续区间可以合并,操作次数为(b - a)次
  • 这个操作为最多 k 次

如何理解呢?

定义把[a, b]连续区间进行合并,则

E[a,b]合并的时间消耗=(∑i=ai=bPi)∗Ta,E[a, b]合并的时间消耗=(\sum_{i=a}^{i=b} P_i) * T_a,E[a,b]合并的时间消耗=(i=a∑i=b​Pi​)∗Ta​,
E[a,b]合并的代价=cost[a,b]=∑i=a+1i=bCiE[a, b]合并的代价= cost[a, b]=\sum_{i=a+1}^{i=b} C_i E[a,b]合并的代价=cost[a,b]=i=a+1∑i=b​Ci​

能理解这个核心的概念后,那个这个 dp 就相对容易解了

  1. 定义状态dp[i][j]为前i项,使用j次merge操作的最小时间/代价dp[i][j] 为前 i 项,使用 j 次merge 操作的最小时间/代价dp[i][j]为前i项,使用j次merge操作的最小时间/代价
  2. 转移方程dp[i+1+s][j+s]=min⁡s∈[0,k−j]dp[i][j]+E[i+1,i+1+s]dp[i + 1 + s][j + s] = \min_{s\in[0, k - j]} { dp[i][j] + E[i + 1, i + 1 + s] }dp[i+1+s][j+s]=s∈[0,k−j]min​dp[i][j]+E[i+1,i+1+s]
  3. 结果ans=min⁡j∈[0,k]dp[n−1][j] ans = \min_{j\in[0, k]} { dp[n - 1][j] } ans=j∈[0,k]min​dp[n−1][j]

时间复杂度为O(n∗k2)O(n*k^2)O(n∗k2)

#include<bits/stdc++.h>usingnamespace std;constint64_t inf =(int64_t)1e18;structW{int t, p, c;W(){}W(int t,int p,int c):t(t),p(p),c(c){}};structE{int64_t p = inf;int64_t c =0;// 重定义<, + booloperator<(const E&rhs)const{return p != rhs.p ? p < rhs.p : c < rhs.c;} E operator+(const E&rhs)const{return{p+rhs.p, c+rhs.c};}};intmain(){int n, k; cin >> n >> k; vector<W>tasks(n);for(int i =0; i < n; i++){ W &w = tasks[i]; cin >> w.t >> w.p >> w.c;}// 预处理,时间和费用的前缀和 vector<int64_t>pre_p(n +1,0); vector<int64_t>pre_c(n +1,0);for(int i =0; i < n; i++){ pre_p[i +1]= pre_p[i]+ tasks[i].p; pre_c[i +1]= pre_c[i]+ tasks[i].c;}// 定义 dp[i][j], 前i项使用j次操作的最小时间/费用  vector<vector<E>>dp(n,vector<E>(k +1));for(int i =0; i <= k && i < n; i++){ dp[i][i]={(pre_p[i +1]- pre_p[0])* tasks[0].t, pre_c[i +1]- pre_c[1]};}// 刷表for(int i =0; i < n; i++){for(int j =0; j <= k; j++){for(int s =0; s + j <= k && i + s +1< n; s++){ E tmp ={(pre_p[i + s +2]- pre_p[i +1])* tasks[i +1].t, pre_c[i + s +2]- pre_c[i +2]}; E tmp2 = dp[i][j]+ tmp;if(tmp2 < dp[i + s +1][j+s]){ dp[i + s +1][j + s]= tmp2;}}}} E ans ={inf,0};for(int i =0; i <= k; i++){if(dp[n -1][i]< ans){ ans = dp[n -1][i];}} cout << ans.p <<" "<< ans.c <<"\n";return0;}

写在最后

在这里插入图片描述

Read more

能明显感受到,前端岗的新风口已经悄悄来了

最近和身边做前端的同行、几家科技公司的前端负责人聊下来,越聊越有感触——我们熟悉的那个前端岗,好像真的在悄悄变样了。以前总有人说前端是“切图仔”,上限低、可替代性强,甚至每年都有“前端已死”的论调,但这段时间明显能感觉到,风向彻底变了。不再是单纯比谁能更快还原设计稿、谁能搞定浏览器兼容性,行业对前端的需求,正在往更深入、更多元的方向走,那些悄悄布局新方向的人,已经开始抓住新机会了。这个新风口没有大张旗鼓的宣传,却在招聘市场、技术落地的细节里,藏满了信号。 🌪️跨端、工程化、可视化…… 企业的数字化转型,把前端推到了 C 位! 如果你还在原地踏步,就真的要被后浪拍在沙滩上了。 想要抓住这波风口,实现薪资翻倍? 这5 大核心能力,是你升咖的入场券:🎫 1️⃣ 跨端开发 📱:Uni-app/Taro/Flutter,一套代码跑遍全端,做真正的 “全栈”。 2️⃣ 工程化搭建 🏗️:Webpack/

WebP革命:从格式之争到WordPress性能优化的实战解析

WebP革命:从格式之争到WordPress性能优化的实战解析 当你在手机上浏览一个图片丰富的网站时,是否经常遇到页面加载缓慢、图片显示卡顿的情况?这背后往往与网站使用的图片格式密切相关。传统JPEG和PNG格式虽然普及,但在现代网页性能优化中已经显得力不从心。Google推出的WebP格式正在悄然改变这一局面——它能在保持同等画质的前提下,将图片体积缩减25%-35%,显著提升页面加载速度。 1. WebP技术解析:为何它能颠覆传统图像格式 WebP并非简单的另一种图片格式,而是Google基于VP8视频编码技术开发的全新一代图像解决方案。它的核心优势在于采用了更先进的预测编码算法,能够更高效地压缩图像数据。 与传统格式相比,WebP具有三大技术突破: * 有损压缩效率:在相同SSIM(结构相似性)指标下,比JPEG小25%-34% * 无损压缩效率:比PNG小26%左右,同时支持透明度通道 * 动画支持:可替代GIF,提供更高画质和更小体积 技术指标对比表: 特性JPEGPNGWebP压缩类型有损无损有损/无损透明度支持不支持支持支持动画支持不支持不支持支

WebGIS + 无人机 + AI:下一代智能巡检系统?

WebGIS + 无人机 + AI:下一代智能巡检系统?

WebGIS 遇上无人机,再叠加 AI 能力,巡检不再只是“看画面”,而是变成“智能决策系统”。 一、为什么 WebGIS + 无人机 + AI 是趋势? 在传统巡检场景中: * 电力巡检 → 人工拍照 * 工地巡查 → 人工记录 * 农业监测 → 靠经验判断 * 安防巡逻 → 事后回放 问题: * 数据无法实时分析 * 缺乏空间关联 * 没有智能预警能力 * 无法形成可视化决策系统 而结合: * WebGIS(三维可视化) * 无人机(数据采集) * AI(智能识别与分析) 我们可以构建: 一个真正的“空天地一体化智能巡检系统” 二、整体技术架构设计 1、系统分层架构 ┌──────────────────────────────┐ │ 前端可视化层 │ │ Cesium + Three.js + WebGL │ └──────────────┬───────────────┘ │ ┌──────────────▼───────────────┐ │ 业务中台层 │ │ AI推理

前端Vue3基础教程超全——下载学习2026.2.5-2.9

一、Vue简介(什么是Vue,为什么选择Vue,开发前的准备) 1.Vue是一款优秀的前端渐进式框架,是目前企业主流的框架技术需求,并且学习难度低。 2.它基于标准的HTML、CSS、JS构建,并提供一套声明式、组件化的编程模型。 3.渐进式框架:是一个框架,也是一个生态。可以某个功能单个、模块中使用,甚至在完整的项目中使用。 4.Vue官方文档: 简介 | Vue.jshttps://cn.vuejs.org/guide/introduction5.Vue API风格:选项式API和组合式API(两种风格不一样但是实现的效果是一致的) 选项式API(Vue2): <script> export default { data() { return { count: 0 } }, methods: { increment() { this.