OJ刷题 第十三篇

22102 - 将字符串反序

时间限制 : 1 秒

内存限制 : 128 MB

请将一个给定的字符串反序(字符长度为1到10000,且有可能包含空格)。

输入

反序前的字符串

输出

反序后的字符串

样例

输入

abcd

输出

dcba

答案:

C++版本1:(掌握)

#include<iostream>
#include<string>//getline()头文件
using namespace std;
int main() {
	string s;
	getline(cin, s);
	for (int i = s.length()-1; i >= 0; i--) {
		cout << s[i];
	}
	return 0;
}

 分析:C++输入字符串,要想输入包含空格的字符串,只用cin是不行的,第一种方式是用getline()函数来输入。且它只能输入string类型的字符串,对字符组它是不能这样输入!它遇到回车时才结束。

C++版本2:

#include<iostream>
#include<string.h>
using namespace std;
int main() {
	char s[10000];
	cin.get(s, 10000);
	for (int i = strlen(s) - 1; i >= 0; i--) {
		cout << s[i];
	}
	return 0;
}

分析:输入含空格的字符串,遇到回车结束,第二种方式是cin.get(),它只能对字符数组进行这样输入

C语言版本:(必须掌握)

#include<stdio.h>
#include<string.h>
int main() {
	char s[10000];
	scanf("%[^\n]", s);
	for (int i = strlen(s)-1; i >= 0; i--) {
		printf("%c", s[i]);
	}
	return 0;
}

分析:这种比较智能,scanf限定输入某种字符结束:

如:scanf("%[^\n]")这种呢就是遇到回车符结束,^表示非得意思。^\n就是不能输入回车,否则结束输入。

如:scanf("%[a-z A-Z 0-9]")就是输入字母和数字,输入其他字符则输入结束。

是否通过:

22207 - 破译邮件(难题)

时间限制 : 1 秒

内存限制 : 128 MB

小明收到了一封很奇怪的邮件,里面全是一些符号和数字,但是信上面给出了破译方法,具体方法如下:
(1)将1变为‘A’,2变为‘B’,...,26变为‘Z’;
(2)将‘#’变为一个空格;
(3)忽略‘-’,原始信件中‘-’仅仅用来分割数字。
现请你编程帮助小明破译这封邮件。
 

输入

输入的第一行为一个整数C,表示测试数据的组数。
接下来C行,每行输入一个待破译的字符串,字符串中只包含数字、‘-’和‘#’,长度不超过100。
 

输出

对于每组输入,输出破译后的文本。

样例

输入

4
9#23-9-12-12#19-20-5-1-12#1-20#12-5-1-19-20#15-14-5#10-5-23-5-12
1-14-4#12-5-1-22-5#20-8-5#13-21-19-5-21-13#9-14#20#13-9-14-21-20-5-19
1-6-20-5-18#20-8-5#15-16-5-14-9-14-7#15-6#20-8-5#5-24-8-9-2-9-20-9-15-14
7-15-15-4#12-21-3-11

输出

I WILL STEAL AT LEAST ONE JEWEL
AND LEAVE THE MUSEUM IN T MINUTES
AFTER THE OPENING OF THE EXHIBITION
GOOD LUCK

答案:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
//定义编码信息
typedef struct code {
	int num;
	char c[3];
}code;

int main() {
	int n;
	cin >> n;
	char r[100],s[100];
	code Q[27] = { 0 };
	//初始化编码
	for (int i = 1; i <= 26; i++) {
		Q[i].num = i;
		sprintf(Q[i].c, "%d", Q[i].num);//将整数转为字符串
	}
	Q[0].num = 0;
	Q[0].c[0] = ' ';//下标0存储空格

	while (n >= 1) {
		getchar();//输入字符串之前,注意吃回车符!!
		scanf("%[^\n]", r);
		int j = 0,k=0;
		char tem[3] = { 0 };
		for (int i = 0; i < strlen(r); i++) {
			if (r[i]!='-'&&r[i]!='#') {//找数字
				tem[k++] = r[i];
			}
			//遇到#,要把前面的转为对应的编码,再把#转换为空格
			if (r[i] =='#') {
				tem[k] = '\0';//添加结束符
				for (int m = 1; m <= 26; m++) {
					if (strcmp(Q[m].c, tem) == 0) {
						s[j++] = Q[m].num + 64;
						break;
					}
				}
				s[j++] = Q[0].c[0];
				k = 0;
			}
			//没有遇到#号,直接把数字转换为编码,另外最后一个编码要单独处理
		    if (r[i] == '-'||i==strlen(r)-1) {
				tem[k] = '\0';//添加结束符
				for (int m = 1; m <= 26; m++) {
					if (strcmp(Q[m].c, tem) == 0) {
						s[j++] = Q[m].num + 64;
						break;
					}
				}
				k = 0;
			}
		}
		s[j] = '\0';//添加结束字符
		printf("%s\n", s);
		n--;
	}
	return 0;
}

 分析:这个题难度很大,首先就是把编码分割出来,然后根据分割出来的编码转换为对应的字母,还要注意#号转换为空格的处理,逻辑比较复杂。

在本题中,由于超过9的数字没有直接对应的字母,因此我还用到了sprintf()函数,可以将整数转换为字符串!!这个函数用到了实际的应用。要掌握!

还有就是用来接收编码临时数组tem,接受完一个编码后要添加结束符'\0',目标数组每次处理也是末尾要加结束符'\0'处理。

是否通过:

23102 - 求最大公约数(提高版)

时间限制 : 1 秒

内存限制 : 128 MB

已知两个整数a,b;求它们的最大公约数。

输入

a b (1<=a、b<=10^18)

(1<=a、b<=1018)

输出

a,b的最大公约数

样例

输入

2 6

输出

2

答案:

#include<iostream>
using namespace std;
long long MaxCommon(long long a, long long b) {
	long long max = a > b ? a : b;
	long long min = a < b ? a : b;
	long long r = 0;
	if (max % min == 0) {
		return min;
	}
	else {
		while (min) {
			r = max % min;
			max = min;
			min = r;
		}
		return max;
	}
}
int main() {
	long long a, b;
	cin >> a >> b;
	long long num = MaxCommon(a, b);
	cout << num << endl;
	return 0;
}

分析:这道题写在这里有两个目的:

1、掌握或者温习最大公公约数的求法——辗转相除法

2、不能用之前那种笨的方法来求,对两个数找公共数取模,直到找到最大的那个数,但是这种方法对数据大的时候,就容易超时,是非常笨的方法!

是否通过:

23203 - 最大素因数(重点题,第二次遇到了)

时间限制 : 1 秒

内存限制 : 128 MB

若整数A不仅是X的因数也是素数,我们则称A是X的素因数。现有N个数,请找出这N个数中谁的素因数最大。并输出这个数。

// 将求一个给定整数的最大素因数封装成如下函数
int getMaxFactor(int d){
// 因为1不是素数,所以要有素因数,这个数就必须大于等于2
	if(d<2){
		return -1;
    }
    int k = 2;
    // ... 利用质因数分解,求整数d的最大素因数
    return k;
}

输入

第1行,整数N(1≤N≤5000) 接下来的N行,每行一个整数(1≤每个整数≤20000)

输出

所有整数中素因数最大的是哪个数,如果所有数都没有素因数则输出0

样例

输入

4
36
38
40
42

输出

38

答案:

#include<iostream>
#include<math.h>
using namespace std;
int isSushu(int n) {//判断一个数是不是素数
	if (n == 1) {
		return 0;
	}
	else if (n == 2) {
		return 1;
	}
	else {
		for (int i = 2; i <= sqrt(n); i++) {
			if (n % i == 0) {
				return 0;
			}
		}
		return 1;
	}
}

//求出某个数的最大质因数,本题的核心算法
int MaxNum(int n) {
	if (n == 1) {
		return 0;
	}
	else {
		for (int i = 2; i <= n - 1; i++) {
			while (n % i == 0) {
				n /= i;
				if (isSushu(n)) {
					return n;
				}
			}
		}
		return n;
	}
}
int main() {
	int N;
	cin >> N;
	int a[5000],b[5000];
	for (int i = 0; i < N; i++) {
		cin >> a[i];
	}
	for (int i = 0; i < N; i++) {
		b[i] = MaxNum(a[i]);
	}
	int max = b[0];
	int ans = 0;
	for (int i = 0; i < N; i++) {
		if (max < b[i]) {
			max = max < b[i] ? b[i] : max;
			ans = i;
		}
		
	}
	if (max == 0) {//所有数都没有素因数,即所有数都为1的情况
		cout << 0 << endl;
	}
	else {
		cout << a[ans] << endl;
	}
	return 0;
}

分析:本题难度较大,这道题前面出现过类似的题,就是求那个最大素因数,这个是最难的这个算法是第二次遇到了,很精彩!也是本题的核心。其次是判断一个数是不是素数,这个倒不是很难。

23202 - 回文日期(蓝桥杯2020比赛题,非常漂亮)

时间限制 : 1 秒

内存限制 : 128 MB

在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。 牛牛习惯用8位数字表示一个日期,其中,前4位代表年份,接下来2位代表月份,最后2位代表日期。显然:一个日期只有一种表示方法,而两个不同的日期的表示方法不会相同。牛牛认为,一个日期是回文的,当且仅当表示这个日期的8位数字是回文的。现在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存在的日期是回文的。 一个8位数字是回文的,当且仅当对于所有的i(1 <=i<= 8)从左向右数的第i个数字和第9-i个数字(即从右向左数的第i个数字)是相同的。

例如:

  1. 对于2016年11月19日,用8位数字20161119表示,它不是回文的。
  2. 对于2010年1月2日,用8位数字20100102表示,它是回文的。
  3. 对于2010年10月2日,用8位数字20101002表示,它不是回文的。

每一年中都有12个月份: 其中,1、3、5、7、8、10、12月每个月有31天;4、6、9、11月每个月有30天;而对于2月,闰年时有29天,平年时有28天。

一个年份是闰年当且仅当它满足下列两种情况其中的一种: 1.这个年份是4的整数倍,但不是100的整数倍; 2.这个年份是400的整数倍。

例如: 2000、2012、2016都是闰年。 1900、2011、2014都是平年。

输入

输入包括两行,每行包括一个8位数字。 第一行表示牛牛指定的起始日期。 第二行表示牛牛指定的终止日期。 保证date1和date2都是真实存在的日期,且年份部分一定为4位数字,且首位数字不为0。 保证date1—定不晚于date2。

输出

输出一行,包含一个整数,表示在date1和date2之间,有多少个日期是回文的。

样例

输入

20110101
20111231

输出

1

答案:

#include<iostream>
using namespace std;
int months[13] = { 0,31,29,31,30,31,30,31,31,30,31,30,31 };//默认2月份初始化为29天,到时候只需判断年份是否为闰年即可

bool RunNian(int year) {//判断年份是不是闰年
	if (year % 400 == 0) {
		return true;
	}
	if (year % 4 == 0 && year % 100 != 0) {
		return true;
	}
	return false;
}
int main() {
	int date1, date2;
	cin >> date1 >> date2;
	int count = 0;//记录有几个回文日期
	for (int i = 1; i <= 12; i++) {
		for (int j = 1; j <= months[i]; j++) {
			int year = (j % 10) * 1000 + (j / 10) * 100 + (i % 10) * 10 + (i / 10);//从日期中获取年份
			int date = year * 10000 + i * 100 + j;//把得到的年份和日期拼接成完整日期
			if (i == 2 && j == 29) {
				if (RunNian(year) == false) {//存在一个年份二月是29天,得判断它是不是闰年,如果不是说明不存在该日期
					continue;
				}
			}
			if (date<date1 || date>date2) {//判断日期是否在给定日期的范围之间
				continue;
			}
			count++;
		}
	}
	cout << count << endl;
	return 0;
}

分析:这道题难度颇大,特别是第一次遇到这个题,我刚遇到这个题是先想着怎么从输入的两个合法日期得到这两个日期之间的所有合法范围,这样做行不行?答案是可以,但是会非常麻烦,而且程序可读性不好。这是我最开始的思路。发现写不下去了,逻辑混乱,因此我就去找了资料。由此我们可以看出,蓝桥杯的赛事题还是有水平的。只有千锤百炼,方能遇佛杀佛!

经过查阅资料,我知道,要想得到一个回文日期我们得先知道日期怎么来的?发现回文日期的年份就是通过月份和天数得来的。得到了年份,日期不就出来了吗?因此我们可以通过月份和天数把所有回文日期构造出来,再判断它是不是合法的日期即可。期间还要注意2月份的判断,因为年份有闰年和平年之分,因此我们还需要判断这个年份。

是否通过:

补充:在所有合法日期中(年份在1000到9999之间,月份在1到12之间,天数在1到31之间),有多少个合法的回文日期??并打印它们?? 

只要搞懂蓝桥杯那个思想,我想这是非常简单的,代码如下:

#include<iostream>
using namespace std;
int months[13] = { 0,31,29,31,30,31,30,31,31,30,31,30,31 };//默认2月份初始化为29天,到时候只需判断年份是否为闰年即可

bool RunNian(int year) {//判断年份是不是闰年
	if (year % 400 == 0) {
		return true;
	}
	if (year % 4 == 0 && year % 100 != 0) {
		return true;
	}
	return false;
}
int main() {
	int date1, date2;
	cin >> date1 >> date2;
	int count = 0;//记录有几个回文日期
	for (int i = 1; i <= 12; i++) {
		for (int j = 1; j <= months[i]; j++) {
			int year = (j % 10) * 1000 + (j / 10) * 100 + (i % 10) * 10 + (i / 10);//从日期中获取年份
			int date = year * 10000 + i * 100 + j;//把得到的年份和日期拼接成完整日期
			if (i == 2 && j == 29) {
				if (RunNian(year) == false) {//存在一个年份二月是29天,得判断它是不是闰年,如果不是说明不存在该日期
					continue;
				}
			}
			if (date<date1 || date>date2) {//判断日期是否在给定日期的范围之间
				continue;
			}
			cout << "回文日期:" << date << endl;
			count++;
		}
	}
	cout << "一共有"<< count <<"个合法的回文日期" << endl;
	return 0;
}

运行结果:

 发现一共331个回文日期!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值