大数学家高斯有个好习惯:无论如何都要记日记。
他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210
后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?
高斯出生于:1777年4月30日。
在高斯发现的一个重要定理的日记上标注着:5343,因此可算出那天是:1791年12月15日。
高斯获得博士学位的那天日记上标着:8113
请你算出高斯获得博士学位的年月日。
提交答案的格式是:yyyy-mm-dd, 例如:1980-03-21
请严格按照格式,通过浏览器提交答案。 注意:只提交这个日期,不要写其它附加内容,比如:说明性的文字。
解:
小技巧:利用Excel计算日期差
如上图,输入一个原始日期,在另一个单元格输入 “=” ,然后 鼠标点一下原始日期那个单元格,然后输入计算式,例如上图中是算+100天后的日期,再按一下回车就行了。但是这只支持1970年以后的日期。
回到题目,只能自己手动算:
开始之前有一个问题,1777年4月30日当天是算第一天还是从他的下一天才是第一天
这就要用到例子来判断,先假设1777年4月30日当天为第一天(通过验证例子得出是对的)
注意:一定要细心,最好用纸笔记着哪个数字是表示什么,有一个错了就全错
解:简单枚举
#include
using namespace std;
int main()
{
int y = 1777, m = 4, d = 30;
int days;
cin >> days;
for (int i = 1; i <= days-1; i++)
{
d++;
if ((m == 1 || m == 3 || m == 5 || m == 7 || m == 8|| m == 10) && d == 32)
{
m++;
d = 1;
continue;
}
if ((m == 4 || m == 6 || m == 9 || m == 11) && d == 31)
{
m++;
d = 1;
continue;
}
if ( m == 2 && d == 29 && (!((y%4 == 0 && y%100 != 0) || y%400 == 0)))
{
m++;
d = 1;
continue;
}
if (m == 2 && d == 30 && ((y%4 == 0 && y%100 != 0) || y%400 == 0))
{
m++;
d = 1;
continue;
}
if(m == 12 && d == 32)
{
y++;
m = 1;
d = 1;
continue;
}
}
cout << y << " - " << m << " - " << d << endl;
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
int main()
{
int ans = 0;
for (int a = 1; a < 10; a++)
{
for (int b = 1; b <10; b++)
if (b != a)
{
for (int c = 1; c <10; c++)
{
if (c != a && c!= b)
{
for (int d = 1; d <10; d++)
if (d != a && d!= b && d!= c)
{
for (int e = 1; e <10; e++)
if (e != a && e!= b && e!= c && e!=d)
{
//ab * cde = adb * ce
if ((a*10+b) * (c*100+d*10+e) == (a*100+d*10+b) * (c*10+e))
{
ans++;
//如果不放心,可以输出以便手动计算验证
printf("(%d*10+%d) * (%d*100+%d*10+%d) == (%d*100+%d*10+%d) * (%d*10+%d)\n",a,b,c,d,e,a,d,b,c,e,(a*10+b) * (c*100+d*10+e));
}
}
}
}
}
}
}
printf("%d",ans);
}
小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!
站在台阶前,他突然又想着一个问题:
如果我每一步只能迈上1个或2个台阶。先迈左脚,然后左右交替,最后一步是迈右脚,也就是说一共要走偶数步。那么,上完39级台阶,有多少种不同的上法呢?
请你利用计算机的优势,帮助小明寻找答案。
要求提交的是一个整数。 注意:不要提交解答过程,或其它的辅助说明文字。
解:
模式匹配法:相似问题到现有问题
这道题的母题就是斐波拉契数列计算f(n) = f(n-1) + f(n-2)
这样想:设目前剩下走的台阶有n级,第一步迈一级台阶,往后有n-1级台阶的迈法;第一步迈两级台阶,往后有n-2级台阶的迈法,以此类推。总迈法就是f(n-1) + f(n-2)
#include
using namespace std;
#define N 39
int ans = 0;
//先去掉一个条件:要求走偶数步。 如果只看一次迈一个或两个台阶, 一共有多少种走法?
//那就是斐波拉契数列,求第39项
//f(n = 39) { return f(n-1)+f(n-2) }
// n是剩余要走的台阶 ,step是已走的步数
void f(int n,int step)
{
if (n<0)
{
return;
}
if (n == 0 && step%2 == 0)
{
ans++;
return;
}
f(n-1,step+1);
f(n-2,step+1);
}
int main()
{
f(39,0);
cout << ans << endl;
return 0;
}
答案:51167078
(注:这个方法不是最有效率的,但这只是个填空题,用这样的思路想比较简单)
黄金分割数0.61803… 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。
对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!
言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。
比较简单的一种是用连分数:
这个连分数计算的“层数”越多,它的值越接近黄金分割数。请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。
小数点后3位的值为:0.618
小数点后4位的值为:0.6180
小数点后5位的值为:0.61803
小数点后7位的值为:0.6180340
(注意尾部的0,不能忽略)你的任务是:写出精确到小数点后100位精度的黄金分割值。
注意:尾数的四舍五入! 尾数是0也要保留!
显然答案是一个小数,其小数点后有100位数字,请通过浏览器直接提交该数字。 注意:不要提交解答过程,或其它辅助说明类的内容。
/*
1、转为求斐波那契数列的n和n+1项
2、n取多少?答:直到再增加n,小数点后的101位(因为要四舍五入)没有变化
3、不能用c语言定义的整数型直接运算,要手工地写大数加法和除法(实际上是减法) */
#include
#include
#include
#include
using namespace std;
int n = 50;
//大数的加减乘除计算的模板,最好能背下来,要用到的时候可以直接敲出来
//下面的计算函数是针对本题的,并不完整
void i2s(int num, string &str)
{
stringstream ss;
ss << num;
ss >> str;
}
string add(string a,string b)
{
a = a.substr(a.find_first_not_of('0')); //substr:复制子字符串;find_first_not_of:与()中指定的字符串中任意一个字符都不相符的字符的位置地址
b = b.substr(b.find_first_not_of('0')); //此时得到两串开头没有0的新字符串
long long lenA = a.length();
long long lenB = b.length();
long long len = max(lenA, lenB) + 10; //找这两个之间最大长度的那个。
//因为有可能a和b的长度相同,最后两个相加了之后要进一位,所以最大长度应该是这两个中的最大长度+1
//翻转,便于从低位逐步求和
reverse(a.begin(), a.end()); // reverse是的函数,头文件已经包了
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; //tmp是上一位相加后的进位
for (int i = 0; i < len; i++) //跑一下整个len的长度
{
if (i < b.length())
tmp += (ans[i] - '0') + (b[i] - '0'); //-‘0’:转化成数字 //假设为18
else
tmp += (ans[i] - '0');
//tmp最多是两个9相加得 18,此时就要进位,然后ans[i]位只留个位数,把进位放到tmp
ans[i] = tmp % 10 + '0'; //8 8+'0' //假如上一行算得18,此时ans[i]=8,要把数字转回字符串
tmp /= 10; //按假设,则此时tmp=1
}
//要返回的时候要再翻转
reverse(ans.begin(), ans.end());
return ans.substr(ans.find_first_not_of('0'));
}
int cmp(string a, string b)
{ //在本题情况下,补0都是在后面补的
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;
}
}
//此处,a一定大于等于b
string subtract(string a, string b)
{
//完整的减法里面呢,a可以小于b,这时结果为负数,交换a b进行下面的代码
// 但是本题这里已经可以确定a一定大于等于b了(不是的话也不会进入while执行这个函数
//1.翻转
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
//2.按位做减法
for (int i = 0; i < b.length(); i++)
{
if (a[i] >= b[i])
{
a[i] = a[i] - b[i] + '0'; //要加'0'转回string
}
else //a
{
int k = 1; //k为向后借的位数(因为不能确定它的下一位能不能借不能就再下一位,类推)
while (a[i+k] == '0') //想要借位的那个数是0的话,就没法借,要再向下一位借,而借完之后这一位就变成9
{
a[i+k] = '9';
k++;
}
//这里可以保证i+k这一位上不是0 (因为是0的话就还要进while)
a[i+k] = a[i+k] - '1' + '0'; //a[i+k]和'1'两个都是字符,他们的差就是他们在ASCII码上的差值,是一个数字,所以要+'0'转化回字符
a[i] = (a[i] - '0' + 10) - (b[i] - '0') + '0'; // -'0':把string变成int,+'0':把int变成string。变成整数来计算,算完的结果变成字符来保存
}
}
reverse(a.begin(), a.end());
if (a.find_first_not_of('0') == string::npos) return "0"; //从头到尾都找不到非0(a.find_first_not_of('0')是非0数) (string::npos如果作为一个返回值则表示没有找到匹配项)
//如果没有这个if,当a为0时,a.find_first_not_of('0')会取0的下一个,就会越界
return a.substr(a.find_first_not_of('0')); //从第一个非0字符开始往后截取
}
//除法转换成减法
string divide(string a, string b)
{
//只考虑a
string ans = "0."; //因为a
//转化成减法
for (int i = 0; i < 101; i++)
{ //101次
a.append("0"); //每次在后面补0
int t = 0;
while (cmp(a,b) >= 0) //a>b或a=b,都要做减法,就算是a=b,也要再减一次 (如果不满足,就会回去补0)
{ //ps:a=b的话就表示除尽了,但在本题中是不会出现这种情况的,因为是无限不循环小数
a = subtract(a,b); //不停地做减法
t++; //记录做了多少次减法
}
string t_str;
i2s(t,t_str); //把t改成string
ans.append(t_str);
}
return ans;
}
int main()
{
//在本题中,a一定是小于b的
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-1项和第n项
string ans = divide(a,b);
cout << ans << endl;
cout << ans.length()-2 << endl; //看小数部分是不是101位
return 0;
}
n不够大时,前100位数是不稳定的,下面要不断增大n,直到试出输出不变为止:
n=50时,输出为:0.61803398874989484820740990001204904326284254042472288566070913139408284656461170787663185198760678802
n=100时,输出为:0.61803398874989484820458683436563811772031274396379568575359185108829019869887522987627156252996318428
n=200时,输出为:0.61803398874989484820458683436563811772030917980576286213544862270526046281890244971288825799042314041
n=300时,输出为:0.61803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748
n=400时,输出为:0.61803398874989484820458683436563811772030917980576286213544862270526046281890244970720720418939113748
此时可看到数据已经稳定了
所以答案是(记得要四舍五入):0.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911375
如下的代码判断 needle_start指向的串是否为haystack_start指向的串的前缀,如不是,则返回NULL。
比如:“abcd1234” 就包含了 “abc” 为前缀
char* prefix(char* haystack_start, char* needle_start)
{
char* haystack = haystack_start;
char* needle = needle_start;
while(*haystack && *needle){
if(______________________________) return NULL; //填空位置
}
if(*needle) return NULL;
return haystack_start;
}
请分析代码逻辑,并推测划线处的代码,通过网页提交。 注意:仅把缺少的代码作为答案,千万不要填写多余的代码、符号或说明文字!!
ps:遇到代码填空题,先把代码复制到编译器,加上头文件,让他可以编译
解:
#include
using namespace std;
//haystack_start 母串
//needle_start 前缀
char* prefix(char* haystack_start, char* needle_start)
{
char* haystack = haystack_start;
char* needle = needle_start; //前缀
while(*haystack && *needle){ //两个指针都没有越界 (指针+*表示指针指向的内容,如果越界,会返回false)
//if(______________________________) return NULL; //填空位置
//需要移动并判断
if (*(haystack++) != *(needle++)) return NULL; //先*取了内容才到++指针往下一位移动
//就是两个字符串逐个字符往下比较,直到比完都没有不相等的(needle_start是前缀,长度肯定<=haystack_start,肯定是needle_start先比完)
//needle_start都比完了也没有不相等的说明needle_start是haystack_start的前缀,返回haystack_start
//反之,没有越界(说明没比完)的时候就有不相等的,needle_start就不是前缀,返回NULL
}
if(*needle) return NULL;
return haystack_start;
}
int main()
{
cout << prefix("abc123","abc") << endl;
return 0;
}
答案:*(haystack++) != *(needle++)