2021年第⼗⼆届蓝桥杯省赛真题(CC++⼤学B组)
⽬录
题⽬A:空间(5分)
题⽬描述
⼩蓝准备⽤256MB 的内存空间开⼀个数组,数组的每个元素都是 32 位⼆进制整数,如果不考虑程序占⽤的空间和维护内存需要的辅助空间,请问256MB 的空间可以存储多少个32 位⼆进制整数?
答案提交
  这是⼀道结果填空的题,你只需要算出结果后提交即可。本题的结果为⼀个整数,在提交答案时只填写这个整数,填写多余的内容将⽆法得分。67108864
题⽬分析
题⽬代码
#include <stdio.h>
int main() {
printf("%d", 256 >> 2 << 20);
}
题⽬B:卡⽚(5分)
题⽬描述
⼩蓝有很多数字卡⽚,每张卡⽚上都是数字0到9。
⼩蓝准备⽤这些卡⽚来拼⼀些数,他想从1开始拼出正整数,每拼⼀个,就保存起来,卡⽚就不能⽤来拼其它数了。
⼩蓝想知道⾃⼰能从1拼到多少。
例如,当⼩蓝有30张卡⽚,其中0到9各3张,则⼩蓝可以拼出1到10,但是拼11时卡⽚1已经只有⼀张了,不够拼出11。
现在⼩蓝⼿⾥有0到9的卡⽚各2021张,共20210张,请问⼩蓝可以从1拼到多少?3181
提⽰:建议使⽤计算机编程解决问题。
题⽬分析
题⽬代码(1)
#include <stdio.h>
int n, ans, cnt;
int main() {
while (1) {
n = ans;
while (n) {
if (n % 10 == 1) cnt++;
n /= 10;
}
if (cnt < 2021) ans++;
else break;
}
printf("%d", ans);
}
题⽬代码(2)
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
int s[10];
bool check(int x) {
while (x) {
int t = x % 10;
x = x / 10;
if (--s[t] < 0) return false;
}
return true;
}
int main() {
for (int i = 0; i < 10; i++) s[i] = 2021;
for (int i = 1;; i++) {
if (!check(i)) {
//检查该数是否已经⽤完,不够⽤即最后⼀个数为所求的数
cout << i - 1 << endl;
return 0;
}
}
}
题⽬C:直线(10分)
题⽬描述
在平⾯直⾓坐标系中,两点可以确定⼀条直线。如果有多点在⼀条直线上, 那么这些点中任意两点确定的直线是同⼀条。
给定平⾯上 2 × 3 个整点(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z,即横坐标 是 0 到 1 (包含 0 和 1) 之间的整数、纵坐标是 0到 2 (包含 0 和 2) 之间的整数的点。这些点⼀共确定了 11 条不同的直线。
给定平⾯上 20 × 21个整点 (x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z,即横 坐标是 0 到 19 (包含 0 和 19) 之间的整数、纵坐标是 0 到 20 (包含 0 和 20) 之 间的整数的点。
请问这些点⼀共确定了多少条不同的直线。40257
题⽬分析
题⽬代码
//直线
//⼤致思路:依次枚举各个点,每两个点⽣成对应的斜率和截距。最后看有多少个不同的组合,即有多少条不同的直线
//注意事项:类型为double的两个数值a和b,即使数值相同,对应的double值也有可能不同,故在cpp中⽐较两个double值应判断其abs之差是否在很⼩的⼀个范围之内,例如1e-8
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<math.h>
using namespace std;
// 直线的最⼤数
const int N=200000;
int n=0;
struct Line
{
double k;
double b;
//结构体内嵌排序函数
bool operator < (const Line& t) const
{
// k不同的话,k⼩的在前
if(k!=t.k) return k<t.k;
// k相同的话,b⼩的在前
return b<t.b;
}
}l[N];
int main()
{
//枚举⼀下所有的点对
for(int x1=0;x1<20;x1++)
{
for(int y1=0;y1<21;y1++)
{
for(int x2=0;x2<20;x2++)
{
for(int y2=0;y2<21;y2++)
if(x1!=x2)//避免斜率不存在的情况,总共20条竖线
{
double k=(double)(y2-y1)/(x2-x1);
double b=y2-k*x2;
// l[n].k=k;
// l[n].b=b;
// n++;
//数对存下来
l[n++]={k,b};
}
}
}
}
namespace是干嘛的
sort(l,l+n);
int res=1;
for(int i=1;i<n;i++)
// 出截率和斜率不等的就是不同数
{
if(fabs(l[i].k-l[i-1].k)>1e-8||fabs(l[i].b-l[i-1].b)>1e-8)
res++;
}
cout<<res+20<<endl;
return 0;
}
题⽬D:货物摆放(10分)
题⽬描述
⼩蓝有⼀个超⼤的仓库,可以摆放很多货物。
现在,⼩蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正⽅体。⼩蓝规定了长、宽、⾼三个互相垂直的⽅向,每箱货物的边都必须严格平⾏于长、宽、⾼。
⼩蓝希望所有的货物最终摆成⼀个⼤的⽴⽅体。即在长、宽、⾼的⽅向上分别堆 L、W、H 的货物,满⾜ n = L × W × H。
给定 n,请问有多少种堆放货物的⽅案满⾜要求。
例如,当 n = 4 时,有以下 6 种⽅案:1×1×4、1×2×2、1×4×1、2×1×2、2 × 2 × 1、4 × 1 × 1。
请问,当 n = 2021041820210418 (注意有 16 位数字)时,总共有多少种⽅案?2430
提⽰:建议使⽤计算机编程解决问题。
题⽬分析
先获得2021041820210418所有质因数,再通过质因数去组合从⽽获得所有的正约数,最后只需在所有的正约数3个乘积为2021041820210418就⾏。
题⽬代码
#include <iostream>
#include <cstring>
#include <algorithm>
// ⽤vector来存储约数
#include <vector>
using namespace std;
// n⽐较⼤,会爆因⼦
typedef long long LL;
int main()
{
LL n;
cin>>n;
// 枚举定义⼀下所有约数
vector<LL> d;
//求n的所有约数个数,三层循环,枚举判断n=a*b*c
for(LL i=1; i*i<=n; i++)
{
if(n%i==0)
{
d.push_back(i);
if(n/i!=i)  d.push_back(n/i);
}
}
cout<< d.size()<< endl;
int res = 0;
//枚举⼀下a,b,c
for(auto a:d)
for(auto b:d)
for(auto c:d)
if(a*b*c==n)
res++;
cout<<res<<endl; //结果:2430
return 0;
}
题⽬E:路径(15分)
题⽬描述
⼩蓝学习了最短路径之后特别⾼兴,他定义了⼀个特别的图,希望到图中的最短路径。
⼩蓝的图由 2021 个结点组成,依次编号 1 ⾄ 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值⼤于 21,则两个结点之间没有边相连;如果 a 和 b 的差的绝对值⼩于等于21,则两个点之间有⼀条长度为 a 和 b 的最⼩公倍数的⽆向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有⼀条⽆向边,长度为 24;结点 15 和结点 25 之间有⼀条⽆向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。10266837
提⽰:建议使⽤计算机编程解决问题。
题⽬分析
题⽬代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2200,M=N*50;
int n;
int h[N],e[M],w[M],ne[M],idx;
int q[N],dist[N];
bool st[N];
int gcd(int a,int b)//欧⼏⾥得算法辗转相除法(递归)求最⼤公约数
{
return b ? gcd(b,a%b):a;
}
void add(int a,int b,int c)//添加⼀条边a->b,边权为c
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void spfa()//求1号点到n号点的最短距离
{
int hh=0,tt=0;
memset(dist, 0x3f,sizeof dist);
dist[1]=0;
q[tt ++]=1;
st[1]=true;
while(hh!=tt)
{
int t=q[hh ++];
if(hh==N) hh=0;
st[t]=false;
for(int i=h[t]; i!=-1; i=ne[i])
{
int j=e[i];
if(dist[j]>dist[t]+w[i])
{
dist[j]=dist[t]+w[i];
if(!st[j])  //如果队列已存在j,则不需要将j重复插⼊
{
q[tt++]=j;
if(tt==N) tt=0;
st[j]=true;
}