当前位置: 首页 > news >正文

2025第十六届蓝桥杯c/c++B组国赛题解

目录

前记:

斐波那契字符串

题目:

思路:

关键代码:

总代码:

项链排列

题目大意:

思路:

总代码:

翻倍

题目大意:

思路:

总代码:

子串去重

题目大意:

思路:

总代码:


前记:

本题解只包含了四道我认为赛时可以做出来的题目,第一道编程题太简单我没加进去,正常比赛中如果做对这五道题其他题的暴力再打满,差不多有90多分国二肯定没问题,国一也差不多。

斐波那契字符串

题目:

斐波那契字符串 S 是由 0 和 1 所组成的字符串,其生成规则如下:

  • S1​=0。
  • S2​=1。
  • 对于任意正整数 n(n≥3),Sn​=Sn−2​+Sn−1​(“+”表示字符串拼接)。

例如:S3​=01、S4​=101、S5​=01101。

在斐波那契字符串 S 中,定义逆序对为满足以下条件的整数对 (i,j):

  • 1≤i<j≤∣S∣(其中 ∣S∣ 表示 S 的长度)。
  • S[i]=1(第 i 个字符为 1)并且 S[j]=0(第 j 个字符为 0)。

现在,给定一个正整数 N,请你计算出 SN​ 中所有逆序对 (i,j) 的总数。由于结果可能很大,请输出其对 109+7 取余后的值。

对于 20% 的评测用例,1≤T≤20,3≤N≤35。

对于 100% 的评测用例,1≤T≤,3≤N≤

思路:

NT都很大,如果对于每一个t都重新求出对于的斐波那契字符串然后再求其逆序对数的话定然得不了全分,此时我们就开始想优化,很明显一个思路方向是:每个新字符串都是由前两个字符串得来的,那么每个新字符串的逆序对数是否也和前两个字符串有关系呢?

答案是显而易见的,必然有关系!

新字符串的逆序对数=前一个字符串的逆序对数+前二个字符串的逆序对数+两个字符串合体之后新增的逆序对数,现在关键就是要确定两个字符串合体之后新增的逆序对数,求出之后直接递推即可,新增逆序对数很明显就是前二个字符串中1的个数*前一个字符串中0的个数,现在问题又变成了求各个字符串中0和1的个数。

这个还是很好求的,也是直接递推上去就行。

关键代码:

for(int i=3; i<N; i++) { cnt0[i] = (cnt0[i-1] + cnt0[i-2]) % mod; cnt1[i] = (cnt1[i-1] + cnt1[i-2]) % mod; } for(int i=3; i<N; i++) { dp[i] = (dp[i-1] + dp[i-2]) % mod; dp[i] = (dp[i] + (cnt1[i-2] * cnt0[i-1]) % mod) % mod; }

总代码:

#include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' const int mod=1e9+7; const int N=1e5+10; int dp[N]; int cnt0[N],cnt1[N]; void solve(){ int n; cin>>n; cout << dp[n]%mod << endl; } signed main(){ ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); int t=1; cin>>t; dp[1]=dp[2]=0; cnt0[1]=1, cnt1[1]=0; cnt0[2]=0, cnt1[2]=1; for(int i=3; i<N; i++) { cnt0[i] = (cnt0[i-1] + cnt0[i-2]) % mod; cnt1[i] = (cnt1[i-1] + cnt1[i-2]) % mod; } for(int i=3; i<N; i++) { dp[i] = (dp[i-1] + dp[i-2]) % mod; dp[i] = (dp[i] + (cnt1[i-2] * cnt0[i-1]) % mod) % mod; } while(t--) solve(); }

项链排列

题目大意:

给定a个‘L’,b个‘Q’,让你拼接成一个字符串,L和Q如果相邻放置,则该字符串变化次数+1,例如:LQ的变化次数是1,LQL的变化次数是2,LQQLLQ的变化次数是3

现在给你一个指定变化次数c,问你如何对这个字符串进行排列才能确保该字符串的变化次数为c,输出字典序最小的那个字符串

思路:

本题是一道贪心

我们先来看一下有哪几种情况会增加变化次数

如上图所示,共有两大种情况,每种情况又分为两种小情况,因为题目要求字典序最小,所以肯定是第一种情况最优,那么此时就需要确定什么时候才满足第一种情况,什么时候满足第二种情况

通过观察很明显发现第一种情况所需的L数>=第二种情况的L数,但是Q数却正好相反,那么巨头到底L数和Q数的满足条件是什么呢?

通过找几个例子就能得到:

int lneed1=c/2+1,qneed1=(c+1)/2; int lneed2=(c+1)/2,qneed2=c/2+1;

对于满足第一种的:

此时可能会有多出的L和多出的Q,此时再考虑安置这些多出来字符

此时需要分两种小情况,例如图中对于第一种小情况,多出来的L直接插到最前面即可,多出来的Q需要插到最后一个Q的后面,也就是最后的字符L前面

而对于第二种小情况,L直接插到最前面不变,此时Q直接插到最后面即可

对于不满足第一种,却满足第二种的:

此时我们发现,定然不会存在多出来的L,否则定然满足第一种条件,此时只需插入多出的Q即可,此时也需分为两种小情况,第一个小情况定然不会存在,因为可以转换成LQLQ,只会存在第二种小情况,此时多出来的Q直接插到最后即可

不满足第一种也不满足第二种的直接输出-1

注意需要特判c=0的情况

总代码:

#include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' const int mod=1e9+7; const int N=1e5+10; void solve(){ int a,b,c; cin >> a >> b >> c; if (c==0) { if (a>0&&b>0) { cout << -1; return ; } for (int i=0;i<a;i++) { cout << 'L'; } for (int i=0;i<b;i++) { cout << 'Q'; } return ; } int lneed1=c/2+1,qneed1=(c+1)/2; int lneed2=(c+1)/2,qneed2=c/2+1; if (a>=lneed1&&b>=qneed1) { int cnt=0; vector<char>ans; ans.push_back('L'); ans.push_back('Q'); cnt++; int n=max(a,b)*2; a--,b--; for(int i=2;i<n;i++) { if (cnt==c) { break; } if (i%2==0) { ans.push_back('L'),a--,cnt++; } else ans.push_back('Q'),b--,cnt++; } if (ans.back()=='Q') { // cout << 123244 << endl; for (int i=0;i<a;i++) { cout << 'L'; } for (int i=0;i<ans.size();i++) { cout << ans[i]; } for (int i=0;i<b;i++) { cout << 'Q'; } }else { for (int i=0;i<a;i++) { cout << 'L'; } for (int i=0;i<ans.size();i++) { if (i!=ans.size()-1) cout << ans[i]; else { for (int j=0;j<b;j++) { cout << 'Q'; } cout << 'L'; i++; } } } }else if(a>=lneed2&&b>=qneed2) { int cnt=0; vector<char>ans; ans.push_back('Q'); ans.push_back('L'); cnt++; int n=max(a,b)*2; a--,b--; for(int i=2;i<n;i++) { if (cnt==c) { break; } if (i%2==0) { ans.push_back('Q'),b--,cnt++; // cout << 1323 << endl; }else ans.push_back('L'),a--,cnt++; } for (int i=0;i<ans.size();i++) { if (i!=ans.size()-1) cout << ans[i]; else { for (int j=0;j<b;j++) { cout << 'Q'; } cout << 'Q'; i++; } } }else { cout << -1 ; } } signed main(){ ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); int t=1; // cin>>t; while(t--) solve(); }

翻倍

题目大意:

给定一个长度为n正整数序列,每次操作可以使得其中一个数翻倍,问你最低操作多少次可以使得该序列整体非递减。

思路:

暴力思路很好想,直接遍历整个数组,如果该数小于前面的数那么该数就一直循环倍增,直至大于等于前面的数

int ans = 0; for(int i = 2; i <= n; i++) { while(a[i] < a[i - 1]) { ans++; a[i] *= 2; } } cout << ans << endl;

但这个肯定得不了满分,我们此时考虑一下优化,优化的主要部分就是这个while循环,我们仔细一想会发现,当前数翻倍的次数只与前一个数有关,为了保证两数的相对大小关系不变,前面的数翻多少倍,那么后面的数同样翻多少倍,此时就会出现一个问题:后面的数有可能多翻好多倍,也有可能少翻了好多倍

此时我们再对倍数进行调整,多翻了就循环--,少翻了就循环++,注意是翻倍所以调整的过程时间复杂度是log级别

for (int i=1;i<n;i++) { cnt[i]=cnt[i-1]; 继承前面数的翻倍情况,保证相对大小不变 int x=a[i],y=a[i-1]; while (x>=y*2) { if (!cnt[i])break; cnt[i]--; y*=2; } 注意循环条件,只有x>=y*2时才会存在多翻的情况 while (x<y) { cnt[i]++; x*=2; } x<y代表少翻了,还得继续翻倍 }

总代码:

#include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' const int mod=1e9+7; const int N=2e5+10; int a[N],cnt[N]; void solve(){ int n; cin >> n; for (int i=0;i<n;i++) { cin >> a[i]; } for (int i=1;i<n;i++) { cnt[i]=cnt[i-1]; int x=a[i],y=a[i-1]; while (x>=y*2) { if (!cnt[i])break; cnt[i]--; y*=2; } while (x<y) { cnt[i]++; x*=2; } } int ans=0; for (int i=0;i<n;i++) { ans+=cnt[i]; } cout << ans << endl; } signed main(){ ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); int t=1; // cin>>t; while(t--) solve(); }

子串去重

题目大意:

给定一个字符串和m次询问,每次询问给两个区间,问你两个区间去重之后有多少个对应位置的字符不同,字符串全是小写字母

思路:

我们可以发现去重之后两个被询问的字串长度定然<=26,此时就可以直接遍历求得答案,主要是如何去重。

我们从字串长度必然小于等于26这个地方起手,我们可以不遍历区间,而是从0-25遍历每个字符,看这个字符在该区间第一次出现的位置

我们需要提前预处理一个二维数组a[i][j]:从i开始字符j第一次出现的位置

vector<vector<int>>a(n+2,vector<int>(26,n+1)); for (int i=n;i>=1;i--) { a[i]=a[i+1]; a[i][s[i]-'a']=i; }

求出来之后即可完成上面的想法:如果第一次出现的位置<区间右端点便可以插入到数组里

int l1,l2,r1,r2; cin >> l1 >> r1 >> l2 >> r2; vector<node>a1,a2; for (int i=0;i<26;i++) { if (a[l1][i]<=r1) a1.emplace_back(i,a[l1][i]); } for (int i=0;i<26;i++) { if (a[l2][i]<=r2) a2.emplace_back(i,a[l2][i]); }

注意插入完需要根据位置进行排序

总代码:

#include<bits/stdc++.h> using namespace std; #define int long long #define endl '\n' const int mod=1e9+7; const int N=2e5+10; int n; struct node { int aa,bb; node(int a, int b) : aa(a), bb(b) {} }; bool cmp(struct node a,struct node b) { return a.bb<b.bb; } void solve() { string s; cin >> s; s=" "+s; int m; n=s.size()-1; vector<vector<int>>a(n+2,vector<int>(26,n+1)); cin >> m; for (int i=n;i>=1;i--) { a[i]=a[i+1]; a[i][s[i]-'a']=i; } while (m--) { int l1,l2,r1,r2; cin >> l1 >> r1 >> l2 >> r2; vector<node>a1,a2; for (int i=0;i<26;i++) { if (a[l1][i]<=r1) a1.emplace_back(i,a[l1][i]); } for (int i=0;i<26;i++) { if (a[l2][i]<=r2) a2.emplace_back(i,a[l2][i]); } sort(a1.begin(),a1.end(),cmp); sort(a2.begin(),a2.end(),cmp); int ans=0; for (int i=0;i<min(a1.size(),a2.size());i++) { if (a1[i].aa!=a2[i].aa)ans++; } ans+=max(a1.size(),a2.size())-min(a1.size(),a2.size()); cout << ans << endl; } } signed main(){ ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); int t=1; // cin>>t; while(t--) solve(); }
http://www.jsqmd.com/news/926240/

相关文章:

  • 方达炬:放飞炬人集团是一个典型的政治体。企业法人仅是放飞炬人集团的最小经济单位。
  • 小白也会:Codex 如何接入 DazeAPI 中转站:从安装、注册到密钥配置
  • Django+Vue养老院健康跟踪系统源码+论文
  • 云南活动执行哪家好?策划/搭建/设备/物料一体化服务
  • KMeans聚类实战:用Python给客户分群,5步搞定RFM模型分析
  • 简单记录---小小的第一步
  • 别再当AI的‘盲盒玩家’:用SHAP和LIME手把手拆解你的机器学习模型(Python实战)
  • 2026年正规GPS定位器TOP5评测:北斗卫星定位器/单北斗定位器/定位器产品/宠物定位器/微型定位器/无线定位器/选择指南 - 优质品牌商家
  • Arm Neoverse V2 PMU架构与性能监控实践
  • Spring Boot 、Spring Cloud 微服务架构认证授权方案
  • 2026年优质镍锻件TOP5推荐:N4纯镍板、N6纯镍板、N6镍卷带、N6镍管、纯镍棒、纯镍管、钛镍合金材料、钛镍材料选择指南 - 优质品牌商家
  • 200万token上下文怎么实现的?GPT-5.5架构拆解
  • UICollectionView基础
  • 国内的七大主流大模型推荐算法有那些差异
  • CC-Switch 全平台部署与使用正式教程【2026-05-31】
  • AI时代艺术家的反抗
  • 【AI问答】GoLang关于代码复用
  • 基于 Isolation Forest + PyOD + Streamlit 的工业设备异常检测与故障预警系统:Python 机器学习项目实战
  • 用Python实战LSTM:从数学建模到量化交易,手把手复现华中杯B题(附完整代码)
  • 2026年苏州本地正规房屋漏水维修三家机构核心能力梳理与场景适配分析 专业防水公司排名推荐(2026年6月防水补漏最新TOP权威排名) - 鼎壹万修缮说
  • Gemini Agent框架实战:从零搭建可商用自动化工作流,含3套已通过SOC2认证的Prompt架构
  • 避开SHL题库陷阱:手把手教你高效准备联想技术岗笔试(附图形推理真题思路)
  • Codex 从安装到国内接入跑通了:Windows / Mac / Linux 小白版记录
  • PYTHON+AI LLM DAY SIXTY-TWO
  • HPC基准测试:核心价值、分类法与优化实践
  • Keil MDK调试中System Viewer外设寄存器缺失问题解决方案
  • 2026年5月更新:深度剖析四川仟屹集团AI今日头条可靠服务商选择之道 - 2026年企业资讯
  • 书匠策AI:我劝你别再熬夜肝课程论文了,这个工具真的能救命
  • 方达炬:方家 将用5到10年时间建设【高福利家庭】
  • VirtualBox 7.0.x 在Win10/11上启动报错supR3HardenedWinReSpawn?保姆级修复教程(含注册表修改与驱动安装)