第十一届蓝桥杯省赛第一场C++ A/B组 真题题解(详细讲解+代码分析)看这篇就够了~~~
Posted 满天星!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十一届蓝桥杯省赛第一场C++ A/B组 真题题解(详细讲解+代码分析)看这篇就够了~~~相关的知识,希望对你有一定的参考价值。
第十一届蓝桥杯省赛第一场C++ A/B组 真题题解
整除序列
题目描述
有一个序列,序列的第一个数是 n,后面的每个数是前一个数整除 2,请输出这个序列中值为正数的项。
输入格式
输入一行包含一个整数 n。
输出格式
输出一行,包含多个整数,相邻的整数之间用一个空格分隔,表示答案。
数据范围
1≤n≤1018
输入样例:
20
输出样例:
20 10 5 2 1
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
ll n;
cin>>n;
while(n>0)
cout<<n<<" ";
n>>=1;
return 0;
解码
题目描述
小明有一串很长的英文字母,可能包含大写和小写。
在这串字母中,有很多连续的是重复的。
小明想了一个办法将这串字母表达得更短:将连续的几个相同字母写成字母 + 出现次数的形式。
例如,连续的 5 个 a,即 aaaaa,小明可以简写成 a5(也可能简写成 a4a、aa3a 等)。
对于这个例子:HHHellllloo,小明可以简写成 H3el5o2。
为了方便表达,小明不会将连续的超过 9 个相同的字符写成简写的形式。
现在给出简写后的字符串,请帮助小明还原成原来的串。
输入格式
输入一行包含一个字符串。
输出格式
输出一个字符串,表示还原后的串。
数据范围
输入字符串由大小写英文字母和数字组成,长度不超过 100。
请注意原来的串长度可能超过 100。
输入样例:
H3el5o2
输出样例:
HHHellllloo
AC代码
#include<bits/stdc++.h>
using namespace std;
int main()
string s;
cin>>s;
for(int i=0;i<s.size();i++)
if(s[i]>='0'&&s[i]<='9')
int t=s[i]-'0'-1;
while(t--)
cout<<s[i-1];
else cout<<s[i];
return 0;
走方格
题目描述
在平面上有一些二维的点阵。
这些点的编号就像二维数组的编号一样,从上到下依次为第 1 至第 n 行,从左到右依次为第 1 至第 m 列,每一个点可以用行号和列号来表示。
现在有个人站在第 1 行第 1 列,要走到第 n 行第 m 列。
只能向右或者向下走。
注意,如果行号和列数都是偶数,不能走入这一格中。
问有多少种方案。
输入格式
输入一行包含两个整数 n,m。
输出格式
输出一个整数,表示答案。
数据范围
1≤n,m≤30
输入样例1:
3 4
输出样例1:
2
输入样例2:
6 6
输出样例2:
0
思路
动态规划
f[i][j] 表示从点 (1,1) 走到点 (n,m) 的方案数。
如果 i,j都是偶数,那么特判为 0。
否则只能从上边或者左边转移过来,即f[i][j] = f[i - 1][j] + f[i][j - 1]
边界情况:f[i][1] = f[1][j] = 1
AC代码
#include<bits/stdc++.h>
using namespace std;
int f[40][40];
int main()
int n,m;
cin>>n>>m;
f[1][1]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(i==1&&j==1) continue;
if(i%2||j%2) f[i][j]=f[i-1][j]+f[i][j-1];
cout<<f[n][m]<<endl;
return 0;
整数拼接
题目描述
给定一个长度为 n 的数组 A1,A2,⋅⋅⋅,An。
你可以从中选出两个数 Ai 和 Aj(i 不等于 j),然后将 Ai 和 Aj 一前一后拼成一个新的整数。
例如 12 和 345 可以拼成 12345 或 34512。
注意交换 Ai 和 Aj 的顺序总是被视为 2 种拼法,即便是 Ai=Aj 时。
请你计算有多少种拼法满足拼出的整数是 K 的倍数。
输入格式
第一行包含 2 个整数 n 和 K。
第二行包含 n 个整数 A1,A2,⋅⋅⋅,An。
输出格式
一个整数代表答案。
数据范围
1≤n≤105,
1≤K≤105,
1≤Ai≤109
输入样例:
4 2
1 2 3 4
输出样例:
6
思路
拼接两个整数比如 12 和 345 ,得出的 12345 就等于12 ✖ 10 ^ 3 + 345,34512等于345 ✖ 10 ^ 2 + 12。
因此本题就相当于求Ai和Aj其(Ai + Aj * 10 ^ len(Ai)) % k = 0这一等式,其中len(Ai)是Ai的位数。
将上述等式转化为 (Aj * 10 ^ len(Ai)) %k =Ai % k
因此本题就成了首先枚举 Ai ,然后求有几个 Aj 其乘以10的 len(Ai)次方 % k = Ai % k。
因此,创建一个二维数组s[i][j],这个数组就表示 (某个数 ✖ 10 ^ i)% k = j 的数量
所以本题就转换为每次枚举一个Ai,然后计算出其%k的数来,然后再算出Ai的位数len,然后去寻找 s[len][Ai % k] 的大小,
就能得知有多少个数满足条件,同时也就是答案数。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int s[11][N];//表示某个数*10^i%k==j的数量
ll a[N];//存放n个数
int main()
int n,k;
cin>>n>>k;
for(int i=0;i<n;i++)
cin>>a[i];
ll res=0;
//预处理s数组
for(int i=0;i<n;i ++)
ll t=a[i]%k;
for(int j=0;j<11;j++)//因为题目中给出的最大数是10^9
s[j][t]++;
t=t*10%k;
//循环数组计算答案
for(int i=0;i<n;i++)
ll t=a[i]%k;
int len=to_string(a[i]).size();//将这个数字转化为字符串,再判断转换后的字符串的位数就等于这个数字本身的位数
res+=s[len][(k - t) % k];
//判重
ll x=t;
while(len--) x=x*10%k; //等价于求a[i]乘以10^len的余数,同上面的预处理求法一样
if(x==(k - t)%k) res--;
cout << res << endl;
return 0;
网络分析
题目描述
小明正在做一个网络实验。
他设置了 n 台电脑,称为节点,用于收发和存储数据。
初始时,所有节点都是独立的,不存在任何连接。
小明可以通过网线将两个节点连接起来,连接后两个节点就可以互相通信了。
两个节点如果存在网线连接,称为相邻。
小明有时会测试当时的网络,他会在某个节点发送一条信息,信息会发送到每个相邻的节点,之后这些节点又会转发到自己相邻的节点,直到所有直接或间接相邻的节点都收到了信息。
所有发送和接收的节点都会将信息存储下来。
一条信息只存储一次。
给出小明连接和测试的过程,请计算出每个节点存储信息的大小。
输入格式
输入的第一行包含两个整数 n,m,分别表示节点数量和操作数量。
节点从 1 至 n 编号。
接下来 m 行,每行三个整数,表示一个操作。
如果操作为 1 a b,表示将节点 a 和节点 b 通过网线连接起来。当 a = b 时,表示连接了一个自环,对网络没有实质影响。
如果操作为 2 p t,表示在节点 p 上发送一条大小为 t 的信息。
输出格式
输出一行,包含 n 个整数,相邻整数之间用一个空格分割,依次表示进行完上述操作后节点 1 至节点 n 上存储信息的大小。
数据范围
1≤n≤10000,
1≤m≤105,
1≤t≤100
输入样例1:
4 8
1 1 2
2 1 10
2 3 5
1 4 1
2 2 2
1 1 2
1 2 4
2 2 1
输出样例1:
13 13 5 3
思路
并查集 树上差分
我们通过并查集合并连通块,保证同一个连通块内的点同属一个集合
对于每一个合并操作,找到两个点所属的集合
如果这两个点不在同一连通块,那么我们构造一个新点,使这个新点成为集合合并后的根节点
这样进行 k次有效合并操作后,就会产生 k 个新点
我们所构造的图是若干棵树,编号为 1−n的节点都是树的叶子节点
对于每次连通块累加操作,我们只需要向集合的根节点累加一个值即可
最后对我们所构造出来的一堆树DP(只是遍历一下),把每个点的权值下放到子树中的所有节点中
然后依次输出编号为 1−n的节点的权值即可
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=200010,M=N/2;
int h[N],e[M],ne[M],p[N],f[N],n,m,idx;
void add(int a,int b)
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
int find(int x)
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
void dfs(int u, int fa)
f[u]+=f[fa];
for(int i=h[u];i!=-1;i=ne[i])
int j=e[i];
dfs(j,u);
int main()
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<=n*2;i ++) p[i]=i;
int r=n+1;
while(m--)
int op, a, b;
cin>>op>>a>>b;
if(op==1)
a=find(a),b=find(b);
if(a!=b)
p[a]=p[b]=r;
add(r,a);
add(r,b);
r++;
else
a=find(a);
f[a]+=b;
for(int i=n+1;i<r;i++)
if(p[i]==i) dfs(i, 0);
for(int i = 1; i <= n; i ++)
cout<<f[i]<<' ';
return 0;
超级胶水
题目描述
小明有 n 颗石子,按顺序摆成一排。
他准备用胶水将这些石子粘在一起。
每颗石子有自己的重量,如果将两颗石子粘在一起,将合并成一颗新的石子,重量是这两颗石子的重量之和。
为了保证石子粘贴牢固,粘贴两颗石子所需要的胶水与两颗石子的重量乘积成正比,本题不考虑物理单位,认为所需要的胶水在数值上等于两颗石子重量的乘积。
每次合并,小明只能合并位置相邻的两颗石子,并将合并出的新石子放在原来的位置。
现在,小明想用最少的胶水将所有石子粘在一起,请帮助小明计算最少需要多少胶水。
输入格式
输入的第一行包含一个整数 n,表示初始时的石子数量。
第二行包含 n 个整数 w1,w2,…,wn,依次表示每颗石子的重量。
输出格式
一个整数表示答案。
数据范围
1≤n≤105,
1≤wi≤1000
输入样例1:
3
3 4 5
输出样例1:
47
输入样例2:
8
1 5 2 6 3 7 4 8
输出样例2:
546
思路
当n=2时:ab
当n=3时:ab+(a+b)c=ac+(a+c)b=bc+(b+c)a=ab+ac + bc
当n=4时:ab+(a+b)c+(a+b+c)d=ac+(a+c)b+(a+c+b)d=.....=ab+ac+ad+ bc+bd +cd
以此类推 每个数分别与后面的所有数相乘之和即可
也就等于
当n=2时: ab
当n=3时:ab+ac+bc=ab+(a+b)c
当n=4时:ab+ac+ad+bc+bd+cd=ab+(a+b)c+(a+b+c)*d
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
int n,x;
cin>>n;
ll sum=0,ans=0;
for(int i=1;i<=n;i++)
cin>>x;
sum+=ans*x;
ans+=x;
cout<<sum<<endl;
return 0;
如果觉得写的还不错,那就一键三连吧 ^ v ^
以上是关于第十一届蓝桥杯省赛第一场C++ A/B组 真题题解(详细讲解+代码分析)看这篇就够了~~~的主要内容,如果未能解决你的问题,请参考以下文章