蓝桥杯2013 C/C++程序设计 B组

错误票据

//某涉密单位下发了某种票据,并要在年终全部收回。
//每张票据有唯一的ID号。全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。
//因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。
//你的任务是通过编程,找出断号的ID和重号的ID。
//假设断号不可能发生在最大和最小号。

//要求程序首先输入一个整数N(N < 100)表示后面数据行数。
//	接着读入N行数据。
//	每行数据长度不等,是用空格分开的若干个(不大于100个)正整数(不大于100000)
//	每个整数代表一个ID号。

//	要求程序输出1行,含两个整数m n,用空格分隔。
//	其中,m表示断号ID,n表示重号ID

//样例一:

//输入
//2
//5 6 8 11 9
//10 12 9
//输出
//7 9

//样例二:

//输入
//6
//164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196
//172 189 127 107 112 192 103 131 133 169 158
//128 102 110 148 139 157 140 195 197
//185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190
//149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188
//113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119
//输出
//105 120

//资源约定:
//峰值内存消耗 < 64M
//	CPU消耗 < 1000ms


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

//	所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

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

//	提交时,注意选择所期望的编译器类型。

#include<iostream>
#include <sstream>
#include <algorithm>
#include<string>

using namespace std;

int line;
int ID[10000] = { 0 };
void sti(string &str,int &num)//可以直接用sstream引入stringstream字符串数据流,来实现字符串转换成数子(string to int(sti))//#include <cstdlib> ==int atoi (const char * str);
{
	stringstream ss;
	ss << str;
	ss >> num;
}
int main()
{
	scanf("%d", &line);
	getchar();//能够录入回车
	int n = 0;
	for (int i = 0; i < line; i++)
	{
		string s;
		getline(cin, s);//按行读取数据(cin接受空格输入)
		istringstream iss(s);//s转化成字符串到iss
		string tmp;
		while (getline(iss, tmp, ' '))//按空格位置分割,拷贝到临时字符串变量tmp
		{
			sti(tmp,ID[n++]);//将tmp转成整形,并依次拷贝到data[]
		}
	}
	sort(ID, ID + n);//data从小到大排序
	int a, b;
	for (int i = 0; i < n; i++)
	{
		if (ID[i] == ID[i + 1] - 2)//断层
			a = ID[i] + 1;
		if (ID[i] == ID[i + 1])//重复
			b = ID[i];
	}
	printf("%d %d", a, b);
	return 0;
}

带分数

//100  可以表示为带分数的形式:100 = 3 + 69258 / 714。
//还可以表示为:100 = 82 + 3546 / 197。
//(有规律714*(100-3)=69258;197*(100-82)=3546)
//注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。(全排列)
//类似这样的带分数,100  有  11  种表示法。
//题目要求:
//从标准输入读入一个正整数N(N < 1000 * 1000)
//程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
//注意:不要求输出每个表示,只统计有多少表示法!
//解题:生成1至9的全排列,先在可能的位置插入+,再在可能的位置插入/,验算等式,做计算

//样例一:
// 用户输入:
//100
//程序输出
//11

//样例二:
//用户输入:
//105
//程序输出:
//6

#include<iostream>
#include<string>
#include<sstream>
#include <algorithm>
//#include<cstdlib>

using namespace std;

int ans=0;
void sti(string &str, int &num)//可以直接用sstream引入stringstream字符串数据流,来实现字符串转换成数子(string to int(sti))//#include <cstdlib> ==int atoi (const char * str);
{
	stringstream ss;
	ss << str;
	ss >> num;
}
//int PART(const char *str, int position, int length)//循环地substr截取易导致超时,PART代替substr
//{
//	int RETURN = 0;
//	int t = 1;
//	for (int i = position+length-1; i >=position; i--)
//	{
//		RETURN += (str[i] - '0') * t;
//		t *= 10;
//	}
//	return RETURN;
//}
int N;
int main()
{
	
	scanf("%d", &N);
	string s = "123456789";
	do
	{                                                                       //const char *str=s.c_str();
		for (int i = 1; i <= 7; i++)//插入+,+最大插到7(给/预留位置)
		{
			string a = s.substr(0,i);//+前的串的长度为i                     //=int inta=PART(str,0,i);			                                                                //
			int inta;//=int inta=atoi(a,c_str());                           //
			sti(a,inta);//                                                  //
			if (inta>=N)
			{
				break;
			}
			for (int j = 1; j <= 9-i-1; j++)//返回j+1之后的值
			{
				string b = s.substr(i, j);//+与/之间串的长度为j-i          //=int intb=PART(str,i,j);
				string c = s.substr(i + j);///之后的串的长度为9-j-i        //=int intc=PART(str,i+j,9-j-i);
				int intb;//=int intb=atoi(b,c_str());                      //
				int intc;//=int intc=atoi(c,c_str());                      //
				sti(b, intb);//                                            //
				sti(c, intc);//                                            //
				if (inta+intb/intc==N&&intb%intc==0)//符合条件(需要能整除,因为整数加减乘除会四舍五入)
				{
					ans++;
					printf("%d %d %d\n", inta, intb, intc);//验证
				}
			}
		}
	} 
	while (next_permutation(s.begin(),s.end()));//全排列
	printf("%d", ans);
	return 0;
}

第39级台阶

//小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!
//站在台阶前,他突然又想着一个问题:
//如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?
//请你利用计算机的优势,帮助小明寻找答案。
//递归解题(二叉树)

#include<stdio.h>

int sum;
void f(int n,int step)
{
	if (n < 0)
	{
		return;
	}
	if (n == 0 && step % 2 == 0)
	{
		sum++;
	}
	f(n - 1, step + 1);
	f(n - 2, step + 1);
}
int main() 
{
	f(39, 0);
	printf("%d", sum);
	return 0;
}//斐波那契函数//

翻硬币

//小明正在玩一个“翻硬币”的游戏。
//桌上放着排成一排的若干硬币。我们用* 表示正面,用 o 表示反面(是小写字母,不是零)。
//比如,可能情形是:**oo***oooo
//如果同时翻转左边的两个硬币,则变为:oooo***oooo
//现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币, 那么对特定的局面,最少要翻动多少次呢?
//我们约定:把翻动相邻的两个硬币叫做一步操作。

//  输入
//两行等长的字符串,分别表示初始状态和要达到的目标状态。每行的长度 < 1000
//	输出
//一个整数,表示最小操作步数。

//	用户输入:
//	*o**o***o***
//	*o***o**o***
//	应输出:
//	1
//  再例如:
//  用户输入:
//  **********
//  o****o****
//  应输出:
//  5
//易知出现不同位置的次数必为偶数(奇数无解)
//规律有最小操作步数=两相近的不同位置的脚标差的总和

#include<iostream>
#include<string>

using namespace std;

int main()
{
	string original;//初始状态
	string target;//目标状态
	getline(cin, original);
	getline(cin, target);
	int LONG = original.length();
	int start = -1;
	int ans = 0;
	for (int i = 0; i < LONG; i++)
	{
		if (original[i] != target[i])
		{
			if (start==-1)//还未标记第一个不同的位置
			{
				start = i;//找到第一个不同的位置,给它标记脚标
			}
			else//第一个不同的位置已经标记,现找到第二个不同的位置i
			{
				ans += (i - start);
				start = -1;
			}
		}
		
	}
	cout << ans << endl;
	return 0;
}

高数日记

//大数学家高斯有个好习惯:无论如何都要记日记。
//他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210
//后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?
//高斯出生于:1777年4月30日。
//在高斯发现的一个重要定理的日记上标注着:5343,因此可算出那天是:1791年12月15日。
//高斯获得博士学位的那天日记上标着:8113
//请你算出高斯获得博士学位的年月日。
//提交答案的格式是:yyyy - mm - dd, 例如:1980 - 03 - 21

#include<stdio.h>

int LEAPYEAR(int year)
{
	if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
		return 1;
	else
		return 0;
}

int main()
{
	int year = 1777;
	int mounth = 4;
	int day = 30;
	for (int i = 0; i < 5343 - 1; i++)//由5343验证得 1777年4月30日 算一天,故-1 
	{
		day++;
		if (mounth == 12 && day == 32)
		{
			year++;
			mounth = 1;
			day = 1;
			continue;
		}
		if ((mounth == 1 || mounth == 3 || mounth == 5 || mounth == 7 || mounth == 8 || mounth == 10) && day == 32)
		{
			mounth++;
			day = 1;
			continue;
		}
		if ((mounth == 4 || mounth == 6 || mounth == 9 || mounth == 11) && day == 31)
		{
			mounth++;
			day = 1;
			continue;
		}
		if (mounth == 2 && LEAPYEAR(year) && day == 30)
		{
			mounth++;
			day = 1;
			continue;
		}
		if (mounth == 2 && !LEAPYEAR(year) && day == 29)
		{
			mounth++;
			day = 1;
			continue;
		};
	}
	printf("%d %d %d", year, mounth, day);

	return 0;
}

黄金分割数 

//黄金分割数0.61803… 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。 
//对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!
//言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。
//比较简单的一种是用连分数:
//                       1
//    黄金数 = ---------------------
//                        1
//            1 + -----------------
//                          1
//                 1 + -------------
//                            1
//                     1 + ---------
//                          1 + ...     
// (斐波那契数列的相邻两项之比)               
//这个连分数计算的“层数”越多,它的值越接近黄金分割数。
//请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。
//小数点后3位的值为:0.618
//小数点后4位的值为:0.6180
//小数点后5位的值为:0.61803
//小数点后7位的值为:0.6180340
//(注意尾部的0,不能忽略)
//你的任务是:写出精确到小数点后100位精度的黄金分割值。
//注意:尾数的四舍五入! 尾数是0也要保留!
//(层数增加,小数点后101为不变)
//(小数点位数太长,不能用c语言定义运算,只能手工的写大数运算)

#include<iostream>
#include <string>
#include <algorithm>
#include <sstream>

using namespace std;

int n = 400;//测试n相是否符合要求,调大n值,直到后100位稳定
void its(int &num, string &str)//可以直接用sstream引入stringstream字符串数据流,来实现数字转换成字符串(int to string(its))//#include <cstdlib> =char *itoa(int value, char *string, int radix);
{
	stringstream ss;
	ss << num;
	ss >> str;
}
string add(string a, string b) //大数加法
{
	a = a.substr(a.find_first_not_of('0'));
	b = b.substr(b.find_first_not_of('0'));
	long long lena = a.length();
	long long lenb = b.length();
	long long len = max(lena, lenb) + 10;
	//求和的最大长度(+10为了进位)
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	//翻转,便于低位求和
	string ans(len, '0');
	for (int i = 0; i < lena; i++)
	{
		ans[i] = a[i];
	}
	int tmp = 0;//记录进位的“1”
	for (int i = 0; i < len; i++)
	{
		if (i<b.length())
		{
			tmp += (ans[i] - '0') + (b[i] - '0');
			//字符减'0'可以到相应的整数。现在比如我们要字符‘1’转换成数字1,就这么一个变化,我们看到了大家注意了字符型常量用''括起来的原因是,它们在计算机中都以各自的ASCII表示。
			//而‘1’的对应编码是49的二进制码,但是我们的数字1,就等于1呀,所以为了由原来的‘1’实际上就是49的二进制变成现在的1对应的二进制1,只好用49 - 48 = 1了。
			//但是在ASCII码里‘0’对应的刚好是48的二进制码,所以我们转换的时候只需要‘1’ - ‘0’ = 1;就可以了。而数字的ASCII码是按顺序规定的。所以其它字符要转换成数字都可以用减‘0’来表示。
			//比如‘2’的ASCII是50,而我们要得到数字2,于是用‘2’ - 48 = 2了。
			//大小写字母的转换:先看ASCII码:a~z是97~122的二进制,而A~Z是65~90的二进制编码,于是我们就得出:大写字母 = 小写字母 - 32 ;。当然这里的32我也可以这么写‘Z’ = ‘z’ - '空格'(空格的ASCII码是32).
		}
		else
		{
			tmp += (ans[i] - '0');
		}
			ans[i] = tmp % 10+'0';//+‘0’转回字符
			tmp /= 10;//等于1
	}
	reverse(ans.begin(), ans.end());
	return ans.substr(ans.find_first_not_of('0'));
}
int compare(string a, string b)
{
	unsigned long i1 = a.find_first_not_of('0');
	if (i1 == string::npos)a = '0';
	else a.substr(i1);

	unsigned long i2 = b.find_first_not_of('0');
	if (i2 == string::npos)b = '0';
	else b.substr(i2);

	if (a.length() > b.length())
	{
		return 1;
	}
	else if (a.length() < b.length())
	{
		return -1;
	}
	else//长度相等,大小不等
	{
		if (a < b)
		{
			return -1;
		}
		if (a > b)
		{
			return 1;
		}
		else
			return 0;
	}
}
string subtract(string a, string b)//此时a>b
{
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	for (int i = 0; i < b.length(); i++)
	{
		if (a[i] >= b[i])
		{
			a[i] = a[i] - b[i] + '0';
		}
		else//借位
		{
			int k = 1;
			while (a[i + k] == '0')
			{
				a[i + k] = '9';
				k++;
			}
			a[i + k] = a[i + k] - '1' + '0';
			a[i] = (a[i] - '0' + 10) - (b[i] - '0')+'0';
		}
	}
	reverse(a.begin(), a.end());
	if (a.find_first_not_of('0') == string::npos)
		return "0";
	return a.substr(a.find_first_not_of('0'));
}
string divide(string a, string b)//大数除法→转换成减法
//易知a<b
{
	string ans = "0.";
	for (int i = 0; i < 101; i++)
	{
		a.append("0");//补“0”
		int t=0;
		while (compare(a, b) >= 0)//a>b时,不停地作减法
		{
			a = subtract(a, b);
			t++;//记录减法次数
		}
		string a;
		its(t, a);
		ans.append(a);
	}
	return ans;
}
int main() 
{
	string a = "1";
	string b = "1";
	for (int i = 3;  i <=n;  i++)
	{
		string tmp = b;
		b = add(a, b);
		a = tmp;
		//a,b是斐波那契数列的n和n+1相
	}
	string ans = divide(a, b);
	cout << ans << endl;//结果保留100位小数
	cout << ans.length() - 2 << endl;//小数点算一位
	return 0;
}

连号区间数 

//小明这些天一直在思考这样一个奇怪而有趣的问题:
//在 1 ~ N 的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:
//如果区间[L, R]里的所有元素(即此排列的第 L 个到第 R 个元素)递增排序后能得到一个长度为 R ? L + 1 的 “连续” 数列,则称这个区间连号区间。
//当 N 很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。

//输入格式
//第一行是一个正整数 N(1 ≤ N ≤ 50000),表示全排列的规模。
//第二行是 N 个不同的数字 P i(1 ≤ P i ≤ N),表示这 N 个数字的某一全排列。

//	输出格式
//	输出一个整数,表示不同连号区间的数目。

//	样例输入一:
//	4
//	3 2 4 1

//	样例输出一:
//	7

//	样例输入二:
//	5
//	3 4 2 5 1

//	样例输出二:
//	9

//样例一解释:7个连号区间是:[1,1],[1,2],[1,3],[1,4],[2,2],[3,3],[4,4]→{(3),(2,3),(2,3,4),(1,2,3,4),(2),(4),(5)}各括号内的数能组成长度为R - L + 1 的 “连续” 数列
//样例一解释:9个连号区间是:[1,1],[1,2],[1,3],[1,4],[1,5],[2,2],[3,3],[4,4],[5,5]
//脚标之差等于对应数列的极差

#include<iostream>

using namespace std;

int N;
int array[50000];
int ans = 0;
int main()
{
	scanf("%d", &N);//输入全排列规模
	for (int i = 0; i < N; i++)//输入数组
	{
		scanf("%d", &array[i]);
	}
	for (int i = 0; i < N; i++)//L
	{
		int min = array[i];
		int max = array[i];
		for (int j = i; j < N; j++)//R
		{
			if (array[j] >= max)
			{
				max = array[j];
			}if (array[j] <= min)
			{
				min = array[j];
			}
			if (i == j)//长度为1的数量必连续
			{
				ans++;
			}
			else//else是相邻if的else
			{
				if (max - min + 1 == j - i + 1)//符合规律
				{
					ans++;
				}
				else
				{
					continue;
				}
			}
			printf("%d %d %d\n", i, j, ans);
		}
	}
	printf("%d", ans);
	return 0;
}

马虎的计算 

//小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。
//有一次,老师出的题目是:36 x 495 = ?
//他却给抄成了:396 x 45 = ?
//但结果却很戏剧性,他的答案竟然是对的!!
//因为 36 * 495 = 396 * 45 = 17820
//类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54
//假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)
//能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?
//请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。

#include<stdio.h>

int main()
{
	int sum = 0;
	for (int a = 1; a <=9; a++)
	{
		for (int b = 1; b <= 9; b++)
		{
			if (b != a)
				for (int c = 1; c <= 9; c++)
				{
					if (c != a && c != b)
						for (int d = 1; d <= 9; d++)
						{
							if (d != a && d != b && d != c)
								for (int e = 1; e <= 9; e++)
								{
									if (e != a && e != b && e != c && e != d)
										if ((a * 10 + b) * (c * 100 + d * 10 + e) == (a * 100 + d * 10 + b) * (c * 10 + e))
									sum++;
									printf("(%d * 10 + %d) * (%d * 100 + %d * 10 + %d) == (%d * 100 + %d * 10 + %d) * (%d * 10 + %d)==%d\n",a,b,c,d,e,a,d,b,c,e, (a * 10 + b) * (c * 100 + d * 10 + e));//验证
								}
						}
				}
		}
	}
	printf("sum=%d", sum);
	return 0;
}

前缀判断 

//如下的代码判断 needle_start指向的串是否为haystack_start指向的串的前缀,如不是,则返回NULL(空)。
//比如:"abcd1234" 就包含了 "abc" 为前缀

#include<iostream>

using namespace std;

char* prefix(char* haystack_start, char* needle_start)
{
    char* haystack = haystack_start;//母串
    char* needle = needle_start;//前缀
    while (*haystack && *needle) //两个指针没有越界
    {
        if (*(haystack++)!=*(needle++)) //填空位置      
            //移动指针并判断
            //“++”在后,先取内容,再作移动
           return NULL;//return NULL说明needle_start指向的串不是haystack_start指向的串的前缀
    }
    if (*needle) //needle没有越界
        return NULL;//省略else
                    //else
                    //return haystack_start;
        return haystack_start;
}
int main() 
{
    cout << prefix("abcd1234","abc") << endl;//测试
    return 0;
}
//请分析代码逻辑,并推测划线处的代码,通过网页提交。
//注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!

三部排序 

//一般的排序有许多经典算法,如快速排序、希尔排序等。
//但实际应用时,经常会或多或少有一些特殊的要求。我们没必要套用那些经典算法,可以根据实际情况建立更好的解法。
//比如,对一个整型数组中的数字进行分类排序:
//使得负数都靠左端,正数都靠右端,0在中部。注意问题的特点是:负数区域和正数区域内并不要求有序。可以利用这个特点通过1次线性扫描就结束战斗!!
//以下的程序实现了该目标。
//其中x指向待排序的整型数组,len是数组的长度。

#include<iostream>

using namespace std;

void sort3p(int* x, int len)
{
	int mod = 0;//左端点
	int left = 0;//左边
	int right = len - 1;//右边
	while (mod <= right) 
	{
		if (x[mod] < 0) //左移
		{
			int t = x[left];
			x[left] = x[mod];
			x[mod] = t;
			left++;
			mod++;
		}
		else if (x[mod] > 0) //右移
		{
			int t = x[right];
			x[right] = x[mod];
			x[mod] = t;
			right--;
		}
		else //x[mod]=0
		{
			mod++; //填空位置
			       //0在中部,无需移动,指针继续前移即可
		}
	}
}
int main()//测试
{
	int x[] = { 25,18,-2,0,16,-5,33,21,0,19,-16,25,-3,0 };
	sort3p(x, 14);
	for (int i = 0; i < 14; i++)
	{
		cout << x[i] << endl;
	}return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值