18年12月蓝桥杯校赛

前言

昨天下午参加了蓝桥杯校内选拔赛。
不谈别人,只谈自己,我觉得这次校赛的发挥还算正常,大概做出了5/8或4/5吧,剩下几道题没时间看了。
应该提高做题效率了…

第一题 Excel地址

Excel单元格的地址表示很有趣,它使用字母来表示列号。
比如,
A表示第1列,
B表示第2列,
Z表示第26列,
AA表示第27列,
AB表示第28列,
BA表示第53列,

当然Excel的最大列号是有限度的,所以转换起来不难。
如果我们想把这种表示法一般化,可以把很大的数字转换为很长的字母序列呢?

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

样例输入:
26
样例输出:
Z

样例输入:
2054
样例输出:
BZZ

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

【分析】
这道题最简单,却花了我最多的时间(大概半个小时),原因是自己没有进行预热,导致很晚才进入状态。
这道题的本质就是类似于将10进制转化为26进制,只不过用A到Z表示1到26。

【我的代码】

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100 + 10;
int main()
{
	int n;
	while (cin >> n)
	{
		int a[maxn], cnt = 0;
		while (n)
		{
			int t = (n - 1) % 26 + 1;//这样写不存在0的情况
			a[cnt++] = t;
			n = (n - t) / 26;	//去余降幂
		}
		for (int i = cnt - 1;i >= 0;i--)
			cout << (char)(a[i] + 'A' - 1);
		cout << endl;
	}
	return 0;
}

第二题 排列序数

【问题描述】
如果用a b c d这4个字母组成一个串,有4!=24种,如果把它们排个序,每个串都对应一个序号:
abcd 0
abdc 1
acbd 2
acdb 3
adbc 4
adcb 5
bacd 6
badc 7
bcad 8
bcda 9
bdac 10
bdca 11
cabd 12
cadb 13
cbad 14
cbda 15
cdab 16
cdba 17

现在有不多于10个两两不同的小写字母,给出它们组成的串,你能求出该串在所有排列中的序号吗?

【输入格式】
一行,一个串。
【分析】
考试时候以为自己写错了,结果仔细读题发现没写错…
全都用生成排列,算是对最近一阵学习的算法的练习了吧(笑哭)
【代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 10000 + 10;
int main()
{
	int pos = 0;
	char str[maxn], cpy[maxn];
	cin >> str;
	int len = strlen(str);
	strcpy(cpy, str);
	sort(str, str + len);
	do {
		if (!strcmp(cpy, str)) {
			cout << pos << endl;
			break;
		}
		pos++;

	} while (next_permutation(str, str + len));
	return 0;
}

第三题 稍大的串(DFS或使用STL)

串可以按照字典序进行比较。例如:
abcd 小于 abdc

如果给定一个串,打乱组成它的字母,重新排列,可以得到许多不同的串,在这些不同的串中,有一个串刚好给定的串稍微大一些。科学地说:它是大于已知串的所有串中最小的串。你的任务就是求出这个“稍大的串”。

样例输入:
输入串:
abfxy
样例输出:
abfyx

样例输入:
输入串:
ayyyxxff
样例输出:
fafxxyyy

数据规模约定:
输入的串不超过1000个字符。

特例:
如果已知的串已经是所有重组串中最大的,则原样输出读入的那个串

【分析】
水题,使用dfs生成1–n的全排列,或者直接使用C++STL里的next_permutation(a,a+n)即可。
考试的时候太心急了没有看到特例,哭辽…

【代码】
1.dfs实现

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 10000 + 10;
char str[maxn], mark[maxn], Min[maxn];
int vis[maxn], len = 0;
void dfs(int cur)	//从0开始往里填数, 到cur==len为止
{
	if (cur == len)
	{
		if (strcmp(mark, str) == 1)//如果生成序列比原始序列大
		{
			if (strcmp(mark, Min) == -1)
				strcpy(Min, mark);
		}
		return;
	}
	if (cur >= len) return;
	for (int i = 0;i < len;i++)
	{
		if (!vis[i])
		{
			vis[i] = 1;
			mark[cur] = str[i];
			dfs(cur + 1);
			mark[cur] = '\0';
			vis[i] = 0;
		}
	}
}
int main()
{
	cin >> str;
	len = strlen(str);
	int flag = 1;
	for(int i=0;i<len-1;i++)
		if (str[i] < str[i + 1]) {
			flag = 0;
			break;
		}
	if (flag) {
		cout << str << endl;
		return 0;
	}
	for (int i = 0;i < maxn;i++) Min[i] = 'z';
	memset(vis, 0, sizeof(vis));
	dfs(0);
	cout << Min << endl;
	//system("pause");
	return 0;
}

2.STL里的next_permutation(a,a+n)

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 10000 + 10;
int main()
{
	char str[maxn], cpy[maxn];
	cin >> str;
	int flag = 1;
	for(int i=0;i<len-1;i++)
		if (str[i] < str[i + 1]) {
			flag = 0;
			break;
		}
	if (flag) {
		cout << str << endl;
		return 0;
	}
	int len = strlen(str);
	strcpy(cpy, str);
	sort(str, str + len);
	do {
		if (strcmp(str, cpy) == 1)
		{
			cout << str << endl;
			break;
		}

	} while (next_permutation(str, str + len));
	return 0;
}

第四题 字符串排序

【描述】
一般我们在对字符串排序时,都会按照字典序排序。当字符串只包含小写字母时,相当于按字母表"abcdefghijklmnopqrstuvwxyz"的顺序排序。

现在我们打乱字母表的顺序,得到一个26个字母的新顺序。例如"bdceafghijklmnopqrstuvwxyz"代表’b’排在’d’前,'d’在’c’前,'c’在’e’前……

给定N个字符串,请你按照新的字母顺序对它们排序。

输入:
第一行包含一个整数N。(1 <= N <= 1000)

第二行包含26个字母,代表新的顺序。

以下N行每行一个字符串S。 (|S| <= 100)

输出:
按新的顺序输出N个字符串,每个字符串一行。

样例输出:
5
bdceafghijklmnopqrstuvwxyz
abcde
adc
cda
cad
ddc
样例输出:
ddc
cda
cad
abcde
adc

【分析】
重新生成字典序,并依据新的字典序排序。
将新字典序的每个字符映射成对应位置的ID即可,使用map会很方便。
【代码】

#include<iostream>
#include<cstdio>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 10000 + 10;
map<char, int>mm;
int judge_lower(string str1,string str2)
{
	int flag = 1;
	int len1 = str1.length();
	int len2 = str2.length();
	int max_len = len1 > len2 ? len1 : len2;
	for (int i = 0;i < max_len;i++)
	{
		char ch1 = str1[i], ch2 = str2[i];
		if (mm[ch1] == mm[ch2]) continue;
		else {
			flag = mm[ch1] < mm[ch2] ? 1 : 0;
			break;
		}
	}
	if (flag) return 1;
	return 0;
}
int main()
{
	char buf[27];
	string str[maxn];
	int n;
	cin >> n;
	getchar();
	cin >> buf;
	
	for (int i = 0;i < 26;i++) //为每个字母重新生成字典序
		mm[buf[i]] = i;

	for (int i = 0;i < n;i++)
		cin >> str[i];
	for (int i = 0;i < n;i++)
	{
		for (int j = 0;j < n - i - 1;j++)
		{
			
			if (judge_lower(str[j + 1], str[j])) {
				string temp;
				temp = str[j];str[j] = str[j + 1];str[j + 1] = temp;
			}
		}
	}

	for (int i = 0;i < n;i++)
		cout << str[i] << endl;
	return 0;
}

第五题 偏差排列

【描述】
如果一个1~N的排列P=[P1, P2, … PN]中的任意元素Pi都满足|Pi-i| ≤ 1,我们就称P是1-偏差排列。
给定一个N,请你计算一共有少个不同的排列是1-偏差排列。
例如对于N=3,有3个1-偏差排列:[1, 2, 3], [1, 3, 2], [2, 1, 3]。

输入

一个整数N。
对于50%的数据,1 ≤ N ≤ 15
对于100%的数据,1 ≤ N ≤ 50
输出
一个整数表示答案
样例输入
3
样例输出
3

【分析】
最初使用dfs生成排列,发现搜索超过十层的时候就很难再进行了,观察结果发现是类似于斐波那契数列…

为了提供一种思路,先放出用深搜写的代码…

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 10000 + 10;
int a[maxn];
int vis[maxn], n = 0;
long long cnt = 0;
bool judge()
{
	for (int i = 1;i <= n;i++)
		if (abs(a[i] - i) > 1) return false;
	return true;
}
void dfs(int cur)	//从0开始往里填数, 到cur==len为止
{
	if (cur == n + 1)
	{
		if (judge()) cnt++;
		return;
	}
	if (cur >= n + 1) return;
	for (int i = 1;i <= n;i++)
	{
		if (!vis[i]) {
			vis[i] = 1;
			a[cur] = i;
			dfs(cur + 1);
			vis[i] = 0;
			a[cur] = 0;
		}
	}
}
int main()
{
	cin >> n;
	dfs(1);
	cout << cnt << endl;
	system("pause");
	return 0;
}

简化版:

#include<iostream>
using namespace std;
const int maxn = 50 + 10;
int main()
{
	int n;
	long long a[maxn];
	a[1] = 1;a[2] = 2;a[3] = 3;
	for (int i = 4;i <= 50;i++)
		a[i] = a[i - 1] + a[i - 2];
	while (cin >> n)
		cout << a[n] << endl;
	return 0;
}

第六题 继承王位

H国的国王有很多王子,这些王子各自也都有很多王孙,王孙又各自有很多后代…… 总之,H国王族的族谱形成了一棵以国王为根的树形结构。
根据H国的法律,王族的继承顺位这样规定的:
假设A和B是两位王族
1 如果其中一位是另一位的直系父亲、祖先,则辈份高的王族继承顺位更高
2 否则,假设C是A和B的最近公共祖先。显然A和B一定是C的两位不同子嗣的后代。其中C较年长的子嗣的后代的继承顺位更高
按时间顺序给出所有国王后代的出生和死亡记录,请你计算所有还活着的后代的继承顺位。
输入
第一行包含一个整数N和一个只包含大写字母和数字的字符串,分别代表记录的条数和国王的名字。
以下N行每行包含一条记录:
birth name1 name2 代表name1的儿子name2出生
death name 代表name死亡
1 <= N <= 10000
名字长度不超过20,并且没有重名的王族。
输出
按继承顺位从高到低输出每位王族的名字。(不包括国王)
每个名字一行。
样例输入
4 KING
birth KING ALI
birth KING BOB
birth ALI CARRO
death ALI
样例输出
CARRO
BOB


第七题

小Hi开发了一个在线玩斗地主的游戏平台。现在平台上有N名用户正在寻找对局,其中第i名用户的积分是Ai。
小Hi希望自己的平台可以自动将这N名用户匹配成尽量多的3人牌局。同时他希望一局中的3名用户两两之间的积分差不超过K。
你能帮小Hi实现这个自动对局匹配的算法吗?
假设现在正有7人在寻找对局,积分分别是[30, 31, 30, 34, 33, 32, 34]并且K = 1,这时最多可以匹配出2局:[30, 31, 30]和[34, 33, 34]。
输入
第一行包含两个整数,N和K。 (1 ≤ N ≤ 100000, 1 ≤ K ≤ 100000)
第二行包含N整数Ai。(0 ≤ Ai ≤ 100000)
输出
一个整数表示最多能匹配出的对局数量。
样例输入
7 2
30 31 30 34 33 32 34
样例输出
2


第八题

描述
小Hi的面前摆放了N张卡片,每张卡片都有A和B两面。其中第i张卡片的A面写着一个整数Ai,B面写着一个整数Bi。
一开始所有卡片都是A面向上。现在小Hi必须选择一张卡片,将其翻成B面向上。
设N张卡片向上那一面的数字组成的集合是S,那么游戏的得分是:最小的不属于S的正整数。
例如S={1, 2, 4, 6, 7},则得分是3。
你能算出小Hi最多能得多少分么?
输入
第一行包含一个整数N。
第二行包含N个整数Ai。
第三行包含N个整数Bi。
对于50%的数据,1 ≤ N ≤ 1000
对于100%的数据,1 ≤ N ≤ 100000 1 ≤ Ai, Bi ≤ 1000000
输出
输出最大得分
样例输入
5
1 2 3 5 6
3 4 3 4 4
样例输出
6


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值