2020年蓝桥杯暑假第2次练习赛 历届真题(C++组)

10 篇文章 0 订阅
6 篇文章 0 订阅

A 试题 历届试题 Excel地址

难度:低 题目类型:数学-进制转换

提交此题 评测记录

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

Excel单元格的地址表示很有趣,它使用字母来表示列号。

比如,

A表示第1列,

B表示第2列,

Z表示第26列,

AA表示第27列,

AB表示第28列,

BA表示第53列,

当然Excel的最大列号是有限度的,所以转换起来不难。

如果我们想把这种表示法一般化,可以把很大的数字转换为很长的字母序列呢?

本题目即是要求对输入的数字, 输出其对应的Excel地址表示方式。

样例输入

26

样例输出

Z

样例输入

2054

样例输出

BZZ

数据规模和约定

我们约定,输入的整数范围[1,2147483647]

峰值内存消耗(含虚拟机) < 256M

CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:

main函数需要返回0;

只使用ANSI C/ANSI C++ 标准;

不要调用依赖于编译环境或操作系统的特殊函数。

所有依赖的函数必须明确地在源文件中 #include

不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。

------------------------------

笨笨有话说:

这有点像进制关系,又不完全是。好像末2位是以1当26,末3位是以1当26*26

歪歪有话说:

要是从字母序列转数字还好点,倒过来有点麻烦,不过计算机跑得快啊。

解题思路:
一道类似26进制转换的题目,但要末位数字是26的话表示为‘z’却不进一。

代码如下:

#include<bits/stdc++.h>
using namespace std;
 
int main()
{

	long long int n,m;
	int a[100]; // 存放每一轮的余数 
	
	while(cin>>n)
	{
		int i = 0;
		while(n)
		{
			m = n % 26;// 取余 
			if(m == 0)
			{
				m = 26;	//余数为零,置为26,代表‘Z ’ 
			}	
			n = (n - m) / 26;  
			a[i++] = m;	 //把余数逐步放入数组 
		}
		
		for(int j = i - 1;j >= 0;j--)//倒序输出 
		{
			cout<<char ('A' - 1 + a[j]);
		}		 
	} 
	return 0;
}

B 试题 历届试题 九宫幻方

难度:低 题目类型:基本算法-枚举

提交此题 评测记录

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三阶幻方指的是将1~9不重复的填入一个3*3的矩阵当中,使得每一行、每一列和每一条对角线的和都是相同的。

三阶幻方又被称作九宫格,在小学奥数里有一句非常有名的口诀:“二四为肩,六八为足,左三右七,戴九履一,五居其中”,通过这样的一句口诀就能够非常完美的构造出一个九宫格来。

4 9 2

3 5 7

8 1 6

有意思的是,所有的三阶幻方,都可以通过这样一个九宫格进行若干镜像和旋转操作之后得到。现在小明准备将一个三阶幻方(不一定是上图中的那个)中的一些数抹掉,交给邻居家的小朋友来进行还原,并且希望她能够判断出究竟是不是只有一个解。

而你呢,也被小明交付了同样的任务,但是不同的是,你需要写一个程序~

输入格式

输入仅包含单组测试数据。

每组测试数据为一个3*3的矩阵,其中为0的部分表示被小明抹去的部分。

对于100%的数据,满足给出的矩阵至少能还原出一组可行的三阶幻方。

输出格式

如果仅能还原出一组可行的三阶幻方,则将其输出,否则输出“Too Many”(不包含引号)。

样例输入

0 7 2

0 5 0

0 3 0

样例输出

6 7 2

1 5 9

8 3 4

数据规模和约定

峰值内存消耗(含虚拟机) < 256M

CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:

main函数需要返回0;

只使用ANSI C/ANSI C++ 标准;

不要调用依赖于编译环境或操作系统的特殊函数。

所有依赖的函数必须明确地在源文件中 #include

不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。

--------------

笨笨有话说:

我最喜欢这类题目了。既然九宫幻方一共也没有多少,我就不辞辛劳地一个一个写出来好了。

也不能太过分,好歹用个数组。

解题思路:
某些组合情况不要想繁杂了,这道题就只有几种情况,一一枚举了再匹配就好。

代码如下:

#include<bits/stdc++.h>
using namespace std;

string ss[]= {"672159834","816357492","438951276","294753618",
              "276951438","618753294","834159672","492357816"
             };
             
string ans;
bool fx(char str[],string ss){
	for(int i=0; i<9; i++){
		if(str[i]==ss.at(i))
			continue;
		if(str[i]=='0')
			continue;
		return false;
	}
	return true;
} 

void print(string ans){
	for(int i=0; i<9; i++){
		if(i==2||i==5||i==8)
			cout<<ans.at(i)<<endl;
		else
			cout<<ans.at(i)<<" ";
	} 
} 

int main(){
	char str[10];
	char x;
	int cnt=0;
	int i=0, q=18;
	while(q--){
		cin>>x;
		if(x!=' '&&x!='\n')
			str[i++]=x;
	}	
	for(int i=0; i<8; i++){
		if(fx(str,ss[i])){
			ans=ss[i];
			cnt++;
		}
	}
	if(cnt==1)
		print(ans);
		else
		cout<<"Too Many"<<endl;
}

C 试题 历届试题 拉马车

难度:中等 题目类型:基本算法-模拟

提交此题 评测记录

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

小的时候,你玩过纸牌游戏吗?

有一种叫做“拉马车”的游戏,规则很简单,却很吸引小朋友。

其规则简述如下:

假设参加游戏的小朋友是A和B,游戏开始的时候,他们得到的随机的纸牌序列如下:

A方:[K, 8, X, K, A, 2, A, 9, 5, A]

B方:[2, 7, K, 5, J, 5, Q, 6, K, 4]

其中的X表示“10”,我们忽略了纸牌的花色。

从A方开始,A、B双方轮流出牌。

当轮到某一方出牌时,他从自己的纸牌队列的头部拿走一张,放到桌上,并且压在最上面一张纸牌上(如果有的话)。

此例中,游戏过程:

A出K,B出2,A出8,B出7,A出X,此时桌上的序列为:

K,2,8,7,X

当轮到B出牌时,他的牌K与桌上的纸牌序列中的K相同,则把包括K在内的以及两个K之间的纸牌都赢回来,放入自己牌的队尾。注意:为了操作方便,放入牌的顺序是与桌上的顺序相反的。

此时,A、B双方的手里牌为:

A方:[K, A, 2, A, 9, 5, A]

B方:[5, J, 5, Q, 6, K, 4, K, X, 7, 8, 2, K]

赢牌的一方继续出牌。也就是B接着出5,A出K,B出J,A出A,B出5,又赢牌了。

5,K,J,A,5

此时双方手里牌:

A方:[2, A, 9, 5, A]

B方:[Q, 6, K, 4, K, X, 7, 8, 2, K, 5, A, J, K, 5]

注意:更多的时候赢牌的一方并不能把桌上的牌都赢走,而是拿走相同牌点及其中间的部分。但无论如何,都是赢牌的一方继续出牌,有的时候刚一出牌又赢了,也是允许的。

当某一方出掉手里最后一张牌,但无法从桌面上赢取牌时,游戏立即结束。

对于本例的初始手牌情况下,最后A会输掉,而B最后的手里牌为:

9K2A62KAX58K57KJ5

本题的任务就是已知双方初始牌序,计算游戏结束时,赢的一方手里的牌序。当游戏无法结束时,输出-1。

输入为2行,2个串,分别表示A、B双方初始手里的牌序列。

输出为1行,1个串,表示A先出牌,最后赢的一方手里的牌序。

样例输入

96J5A898QA

6278A7Q973

样例输出

2J9A7QA6Q6889977

样例输入

25663K6X7448

J88A5KJXX45A

样例输出

6KAJ458KXAX885XJ645

数据规模和约定

我们约定,输入的串的长度不超过30

资源约定:

峰值内存消耗(含虚拟机) < 256M

CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:

main函数需要返回0;

只使用ANSI C/ANSI C++ 标准;

不要调用依赖于编译环境或操作系统的特殊函数。

所有依赖的函数必须明确地在源文件中 #include

不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。

----------------------------

笨笨有话说:

不断删除前边的,又要后边添加… 如果用数组,需要开一个大点的,请佛祖保佑在游戏结束前,不会用到数组的边缘。

歪歪有话说:

反正串也不长,不如每次操作都返回一个新的串。

默默有话说:

我一般都不吱声,这是典型的队列结构,动态数组最好,没有?自己造一个呗!

解题思路:
用自己熟悉的数据结构模拟整个游戏过程即可。

代码如下:

#include<bits/stdc++.h>
using namespace std;

string s1,s2;	//双方(A,B)的牌 
stack<char> st;	//双方出的牌 
map<char,bool> mp;	//判断牌是否出现相等 
 
int main(){
	cin>>s1>>s2;
	bool f=true;
	while(s1.size()&&s2.size()){	//当双方的牌都不为空时: 
		if(f){	//f为true时,A方出牌 
			st.push(s1[0]);	//A的第一张牌入栈 
			s1.erase(s1.begin());	//将A的第一张牌删除 
						
			if(mp[st.top()]){	//如果这张牌出现过 
			//为了便于理解,我举个例子: 
			// A手中的牌目前为---A6897  , 双方出掉的牌为 ---46576  (这里的6是A刚刚出掉的牌,6之前出现过,所以是被标记过的) 
				char tmp=st.top();	//记录这张牌的字符  ---- 6 
				mp[st.top()]=false;	//将该张牌取消标记,因为相等的牌要收回 
				s1+=st.top();	//将赢得牌拿走 ----A68976 
				st.pop();	//该张牌出栈 ------4657
				while(tmp!=st.top()){	//如果两张相等的牌之间还有牌  57
					s1+=st.top();  	//A689767   A6897675
					mp[st.top()]=false;	//将这些被A赢走的牌都取消标记 
					st.pop();	//465   46
				}
				s1+=st.top();	//A68976756
				st.pop();	//4
				f=!f;	//将f标记为false 跳出 本次循环 轮到B出牌 
			}else{
				mp[st.top()]=true; 	//将牌标记 
			}
			
		}else{	//下面代码意思和上面差不多 
			st.push(s2[0]);
			s2.erase(s2.begin());
			
			if(mp[st.top()]){
				char tmp=st.top();
				mp[st.top()]=false;
				s2+=st.top();
				st.pop();
				while(tmp!=st.top()){
					s2+=st.top();
					mp[st.top()]=false;
					st.pop();
				}
				s2+=st.top();
				st.pop();
				f=!f;
			}else{
				mp[st.top()]=true;
			}
		}
		f=!f;
	}
	if(s1.size()==0){
		cout<<s2<<endl;
	}else{
		cout<<s1<<endl;
	}
	return 0;
}

D 试题 历届试题 图形排版

难度:高 题目类型:基本算法-模拟 / dfs

资源限制
时间限制:2.0s 内存限制:256.0MB
问题描述
  小明需要在一篇文档中加入 N 张图片,其中第 i 张图片的宽度是 Wi,高度是 Hi。
  假设纸张的宽度是 M,小明使用的文档编辑工具会用以下方式对图片进行自动排版:

1. 该工具会按照图片顺序,在宽度 M 以内,将尽可能多的图片排在一行。该行的高度是行内最高的图片的高度。例如在 M=10 的纸张上依次打印 3x4, 2x2, 3x3 三张图片,则效果如下图所示,这一行高度为4。(分割线以上为列标尺,分割线以下为排版区域;数字组成的矩形为第x张图片占用的版面)

2. 如果当前行剩余宽度大于0,并且小于下一张图片,则下一张图片会按比例缩放到宽度为当前行剩余宽度(高度向上取整),然后放入当前行。例如再放入一张4x9的图片,由于剩余宽度是2,这张图片会被压缩到2x5,再被放入第一行的末尾。此时该行高度为5:

3. 如果当前行剩余宽度为0,该工具会从下一行开始继续对剩余的图片进行排版,直到所有图片都处理完毕。此时所有行的总高度和就是这 N 张图片的排版高度。例如再放入11x1, 5x5, 3x4 的图片后,效果如下图所示,总高度为11:

现在由于排版高度过高,图片的先后顺序也不能改变,小明只好从 N 张图片中选择一张删除掉以降低总高度。他希望剩余N-1张图片按原顺序的排版高度最低,你能求出最低高度是多少么?
输入格式
  第一行包含两个整数 M 和 N,分别表示纸张宽度和图片的数量。
  接下来 N 行,每行2个整数Wi, Hi,表示第 i 个图大小为 Wi*Hi。

对于30%的数据,满足1<=N<=1000
  对于100%的数据,满足1<=N<=100000,1<=M, Wi, Hi<=100
输出格式
  一个整数,表示在删除掉某一张图片之后,排版高度最少能是多少。
样例输入
4 3
2 2
2 3
2 2
样例输出
2
样例输入
2 10
4 4
4 3
1 3
4 5
2 1
2 3
5 4
5 3
1 5
2 4
样例输出
17
数据规模和约定
  峰值内存消耗(含虚拟机) < 256M
  CPU消耗 < 2000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:
  main函数需要返回0;
  只使用ANSI C/ANSI C++ 标准;
  不要调用依赖于编译环境或操作系统的特殊函数。
  所有依赖的函数必须明确地在源文件中 #include
  不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。

解题思路:
模拟做法:小明删除第 i 张图片时,第 1 到 i-1 张图片的排版不变,只有第 i+1 到 N 张图片的排版改变。并且如果用一个数组保存以第k张图片开始排版图片的高度,计算第 i+1 到 N 张图片改变后高度时就不需要全部计算,而只需要计算在换行之前受影响的高度+以之后图片开始排版的高度。
这道题也可以用dfs做,注意一些剪枝优化。

#include<bits/stdc++.h>
using namespace std;

const int MX=1e5+5;
int M,N; //纸张的宽度是 M,加入 N 张图片 
int w[MX],h[MX],t[MX];//wh数组保存宽度和高度,t数组保存以第i张图片开始排版图片的高度

void attach(int i,int &W,int &H) //处理当前行放下该图片后的长度和高度 
{
     
    if(W+w[i]>M) //加入后宽度不够,缩放插入 
        H=max(H,(int)ceil(1.0*h[i]*(M-W)/w[i])); 
    else
        H=max(H,h[i]);
        
    W=min(M,W+w[i]);
}

int calc(int i,int W,int H) //计算在加入i图片的基础上加上i-N后排版的高度 
{
    while(i<N&&W<M) //从第i张图片开始,加入到这一行满为止,得到这一行的H(换行之前受影响的高度),i经过数次++变为了下一行初始插入的图片序号 
        attach(i++,W,H);
        
    return H+t[i]; 
	//因为t是保存了每行以第i张图片开始排版图片的总高度,所以H这一行的高度加上以新行1以新i张图片开始排版的高度t[i]即为 在加入i图片的基础上加上i-N后排版的高度
}

int main()
{
    cin>>M>>N;
    for(int i=0;i<N;i++)
    {
        cin>>w[i]>>h[i];
    }
    
    // t数组初始化保存以每行以第i张图片开始排版图片的总高度
	//(如果第 i 张图片以前排到过某行的第一个位置,那么他后边的排法肯定不变了,后边的高度和也不会变。
	//所以这就需要先把所有的图片(n张)先排一遍,用数组 t 记录一下状态,t[i] = x 表示 第 i 张图片排在了某一行的第一张时,他当前所在的行以及他后边所有行的高度和) 
    for(int i=N-1;i>=0;i--)
    {
        t[i]=calc(i,0,0);
    }
     
    int res=t[0];
    int tmp;
    int pre_h=0;
    int W=0,H=0;
    
    for(int i=0;i<N;i++)
    {
    	//每次去掉第i个图片 
        tmp=calc(i+1,W,H);  //计算去掉第i个图片,后面i-N的总高度 
        res=min(res,pre_h+tmp);//比较去掉第i个图片时总高度和去掉第i-1个图片时的高度,取较小的那一个 
        
        attach(i,W,H); //把第i张图片插入,下一循环去掉第i+1 张图片 
        //如果满了就换行。 
        if(W==M) 
        {
            pre_h+=H;
            W=0;
            H=0;
        }
    }
    
    cout<<res<<endl;
    return 0;
}

附上某大佬此题dfs做法参考:https://blog.csdn.net/u014117943/article/details/104736390/

喜欢或者觉得对你有帮助的话,可以点赞收藏转发喔~

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值