文章目录
2013年蓝桥杯省赛真题解析(上)
(C/C++大学B组)
高斯日记:
#include<iostream>
using namespace std;
bool isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0)||(year % 400 == 0);
}
#define _for(i, x, y) for(int i = x;i < y;i++)
int main(){
int year = 1777;
int month = 4;
int day = 30;
const int mon_arr[] = {-1,31,28,31,30,31,30,31,31,30,31,30,31};
const int days = 8113 - 1;
_for(i,0,days){
//根据当前月份判断当前月的天数
day++;
if(month == 2 && day >= 29){
if(isLeapYear(year))
if(day == 30) {
month = 3;
day = 1;
}
if(!isLeapYear(year))
if(day == 29)
{
month = 3;
day = 1;
}
continue;
}
if(day == mon_arr[month] + 1){
day = 1;
if(month == 12) {
year += 1;
month = 1;
} else
month++;
}
}
cout<<year<<" "<<month<<" "<<day<<endl;
return 0;
}
马虎的算式:
#include<iostream>
#include<set>
using namespace std;
#define _for(i,start,end) for(int i = start;i <= end;i++)
int main(){
//abcde
//ab * cde = adb * ce
int temp1,temp2,count = 0;
set<int> Set;
_for(a,1,9)
_for(b,1,9)
_for(c,1,9)
_for(d,1,9)
_for(e,1,9){
//set写起来简单,但是显然,如果a = b,后面的c,d,e就不用跑了
//这样写效率低下,在本地自己玩可以,若要提交代码的话,性价比不高。
Set.insert(a);
Set.insert(b);
Set.insert(c);
Set.insert(d);
Set.insert(e);
if(Set.size() < 5){
Set.clear();
continue;
}
temp1 = (a*10+b)*(c*100+d*10+e);
temp2 = (a*100+d*10+b)*(c*10+e);
if(temp1 == temp2)
count++;
Set.clear();
}
cout<<count;
return 0;
}
#include<iostream>
using namespace std;
#define _for(i,start,end) for(int i = start;i <= end;i++)
int main() {
//abcde
//ab * cde = adb * ce
int temp1, temp2, count = 0;
_for(a, 1, 9)_for(b, 1, 9) {
if (b != a)
_for(c, 1, 9) {
if (c != a && c != b)
_for(d, 1, 9) {
if (d != a && d != b && d != c)
_for(e, 1, 9) {
if (e != a && e != b && e != c && e != d) {
temp1 = (a * 10 + b) * (c * 100 + d * 10 + e);
temp2 = (a * 100 + d * 10 + b) * (c * 10 + e);
if (temp1 == temp2)
count++;
}
}
}
}
}
cout<<count;
return 0;
}
第39阶台阶:
#include<iostream>
using namespace std;
int walk(int left,int count){
int sum = 0;
if(left - 1 >= 0)
sum += walk(left - 1,count + 1);
if(left - 2 >= 0)
sum += walk(left - 2,count + 1);
if(left == 0)//保证是偶数级台阶
if(count % 2 == 0)
return 1;
else
return 0;
return sum;
}
int main() {
int count = 0;
cout<<walk(39,count);
return 0;
}
注意:
此题为填空题,暴力递归出答案即可。(一个填空题要什么自行车)若考虑记忆背包,则必须想清楚在k这个台阶存2个值,一个是走奇数步的值,一个是走偶数步的值。比如在台阶为0时(就是left=0的时候),奇数步返回0,偶数步返回1。
黄金连分数:
- 转为求斐波拉契的n和n+1项
- n取多少?再增加n,小数点后101位没有变化
- 不能用c语言所定义的整数型直接运算,而要手工地写大数加法和除法(减法)
注:可以用java的大整数库算出答案(比赛能不能背地里用java这就不知道了)
这一题包含了高精度加法、减法、除法。
不是很完善但是指出了大致的思路。
适合用作学习string类的材料
#include<iostream>
#include <algorithm>
#include <cstring>
using namespace std;
string add(string a,string b){
/**
高精度加法模板,
在处理a,b谁长度长的问题上。string ans(len,'0'),再把a拷贝进ans。
我们不用a[i] + b[i]而是用ans[i] + b[i],这样避免a的长度小而导致下标越界。
这样的话,如果b的长度最长也不影响,因为ans后面用'0'填充了。
我们遍历len = max(lenA,lenB)
如果a是最长的,那么当超过b的长度时,我们只加ans[i]
*/
//去除开头的0,"000123" -> "123"
a = a.substr(a.find_first_not_of('0'));
b = b.substr(a.find_first_not_of('0'));
long long lenA = a.length();
long long lenB = b.length();
long long len = max(lenA,lenB)+10;
//翻转便于从低位逐步求和
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
string ans(len,'0');//初始化答案为len长,全部字符为0
//把a拷贝到ans中
for(int i = 0;i < lenA; i++){
ans[i] = a[i];
}
int tmp = 0;
for(int i = 0; i < len; i++){
if(i < b.length())
tmp += (ans[i] - '0') + (b[i] - '0');
else
tmp += (ans[i] - '0');
ans[i] = tmp % 10 + '0';
tmp /= 10;//tmp是上一位相加后的进位
}
reverse(ans.begin(),ans.end());
return ans.substr(ans.find_first_not_of('0'));
}
int cmp(string a,string b){
//防止a全部是0
//unsigned long i1 = a.find_first_not_of('0');
if(a.find_first_not_of('0') == string::npos)a="0";
else a.substr(a.find_first_not_of('0'));
if(b.find_first_not_of('0') == string::npos)b="0";
else b.substr(b.find_first_not_of('0'));
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;
//a == b
else return 0;
}
}
string subtract(string a,string b){
//此函数中a必须大于b
//完整的减法,a可以小于b,结果为负数,交换a,b进行下面的代码
//1.翻转
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
//2.按位做减法
//for(int i = 0;i < b.length(); i++)里面的i++是否和++i等价
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++;
}
//这里可以保证i+k这一位上不是0
//my
a[i+k] = a[i+k] - '1'+'0';
a[i] = (a[i] - '0' + 10) -(b[i] - '0') + '0';
}
}
reverse(a.begin(),a.end());
//使用a.find_first_not_of('0'),要注意若a==b的话,ans = "0";那么找不到非0,那么会越界
//预防一下,就是预防特殊的a == b;
if(a.find_first_not_of('0') == string::npos)return "0";
return a.substr(a.find_first_not_of('0'));
}
void i2s(int t,string &str){
int len_t = 0;
string temp = "0";
if(t == 0)
str.append(temp);
while(t){
temp = t%10 + '0';
str.append(temp);
t /= 10;
len_t++;
}
reverse(str.begin(),str.end());
}
string divide(string a,string b){
//只考虑a <= b的情况
string ans = "0.";//整数部分根据题意一定是这个
//转换成减法
for(int i = 0; i < 101; i++){
a.append("0");
int t = 0;
while(cmp(a,b)>=0){
a = subtract(a,b);//不同做减法
t++;//记录减法做了多少次
}
string t_str;
//我先把i2s注释掉
i2s(t,t_str);
ans.append(t_str);
}
return ans;
}
int main() {
string a = "1";
string b = "1";
for(int i = 3;i <= 500;i++){
string tmp = b;
b = add(a,b);
a = tmp;
}
string ans = divide(a,b);
cout<<ans<<endl;
cout<<ans.length() - 2<<endl;
//拿到答案之后,记得手动4舍5入
return 0;
}
前缀判断:
如下代码判断 needle_start指向的串是否为haystack_start指向串的前缀,如不是,则返回NULL。
比如:“abcd1234”就包含了“abc”;为前缀
#include<iostream>
#include <algorithm>
#include <cstring>
using namespace std;
/**
*
* @param haystack_start 母串
* @param needle_start 前缀
* @return
*/
char* prefix(char* haystack_start,char* needle_start){
//needle_start是否为haystack_start的前缀
char* haystack = haystack_start;
char* needle = needle_start;
while(*haystack && *needle) {
//当2个指针都没越界,且二个指针指向的内容都不相等,指针后移
if (*(haystack++) != *(needle++)) {
return NULL;
}
}
//假设有一个字符串长度短,就发生指针越界,出循环
//if(*needle)说明这个时候needle的指针没有越界,那么就说明haystack比needle要短,
//所以needle_start不是haystack的前缀,返回NULL
if(*needle)
return NULL;
//if(*needle)为假,说明needle比haystack短。在while循环可以看出,
// needle的字符和haystack_start前面的字符相等,说明needle是haystack的前缀。
return haystack_start;
}
int main() {
char a[] = "abcd1234";
char b[] = "abc";
cout<<prefix(a,b);
//或prefix("abcd1234","abc");
return 0;
}