入门训练
《1》Fibonacci数列
问题描述
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。
当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。
输入格式
输入包含一个整数n。
输出格式
输出一行,包含一个整数,表示Fn除以10007的余数。
说明:在本题中,答案是要求Fn除以10007的余数,因此我们只要能算出这个余数即可,而不需要先计算出Fn的准确值,再将计算的结果除以10007取余数,直接计算余数往往比先算出原数再取余简单。
样例输入
10
样例输出
55
样例输入
22
样例输出
7704
心得体会:
其实从题目中可以知道,可以直接求Fn mod 10007=(Fn-1+Fn-2) mod 10007,既为答案。之所以取余是因为Fn可能太大,所以取余存储,这在其他的处理大数据的题中也常常会出现。此题可以用递归算法实现,也可以用循环。
参考代码:
//<循环实现> #include<stdio.h> int f[3],n;//不需要存储中间结果,所以只需要长度为2的素组即可 int main() { f[1]=f[2]=1; scanf("%d",&n); int i=3,t; while(i<=n) { t=(f[1]+f[2])%10007; f[1]=f[2]; f[2]=t; i++; } printf("%d ",f[2]); return 0; } //<递归实现> #include <stdio.h> #include <stdlib.h> int fab(int n) { int r; if(n==1 || n==2) { return 1; } else { return (fab(n-1)+fab(n-2))%10007; } } int main() { int a,r; scanf("%d",&a); while(a!=-1) { r=fab(a); printf("输入:%d,输出余数:%d ",a,r); scanf("%d",&a); } return 0; }
《2》圆的面积
说明:在本题中,输入是一个整数,但是输出是一个实数。
对于实数输出的问题,请一定看清楚实数输出的要求,比如本题中要求保留小数点后7位,则你的程序必须严格的输出7位小数,输出过多或者过少的小数位数都是不行的,都会被认为错误。
实数输出的问题如果没有特别说明,舍入都是按四舍五入进行。
#include <stdio.h> #include <stdlib.h> #define PI 3.14159265358979323 int main() { int r; double s; scanf("%d",&r); s=(double)PI*r*r;//显示加上类型强制转换,以免错误 printf("%.7f",s); return 0; }
《3》序列求和
说明:有一些试题会给出多组样例输入输出以帮助你更好的做题。
一般在提交之前所有这些样例都需要测试通过才行,但这不代表这几组样例数据都正确了你的程序就是完全正确的,潜在的错误可能仍然导致你的得分较低。
说明:请注意这里的数据规模。
本题直接的想法是直接使用一个循环来累加,然而,当数据规模很大时,这种“暴力”的方法往往会导致超时。此时你需要想想其他方法。你可以试一试,如果使用1000000000作为你的程序的输入,你的程序是不是能在规定的上面规定的时限内运行出来。
本题另一个要值得注意的地方是答案的大小不在你的语言默认的整型(int)范围内,如果使用整型来保存结果,会导致结果错误。
如果你使用C++或C语言而且准备使用printf输出结果,则你的格式字符串应该写成%I64d(或%lld)以输出long long类型的整数。
参考代码:
#include<stdio.h>
int main()
{
long long n,result;
scanf("%lld",&n);
printf("%lld",(1+n)*n/2);
return 0;
}
《3》A+B问题
问题描述
输入A、B,输出A+B。
说明:在“问题描述”这部分,会给出试题的意思,以及所要求的目标。
输入格式
输入的第一行包括两个整数,由空格分隔,分别表示A、B。
说明:“输入格式”是描述在测试你的程序时,所给的输入一定满足的格式。 做题时你应该假设所给的输入是一定满足输入格式的要求的,所以你不需要对输入的格式进行检查。多余的格式检查可能会适得其反,使用你的程序错误。
在测试的时候,系统会自动将输入数据输入到你的程序中,你不能给任何提示。比如,你在输入的时候提示“请输入A、B”之类的话是不需要的,这些多余的输出会使得你的程序被判定为错误。
输出格式
输出一行,包括一个整数,表示A+B的值。
说明:“输出格式”是要求你的程序在输出结果的时候必须满足的格式。
在输出时,你的程序必须满足这个格式的要求,不能少任何内容,也不能多任何内容。如果你的内容和输出格式要求的不一样,你的程序会被判断为错误,包括你输出了提示信息、中间调试信息、计时或者统计的信息等。
样例输入
12 45
说明:“样例输入”给出了一组满足“输入格式”要求的输入的例子。 这里给出的输入只是可能用来测试你的程序的一个输入,在测试的时候,还会有更多的输入用来测试你的程序。
样例输出
57
说明:“样例输出”给出了一组满足“输出格式”要求的输出的例子。 样例输出中的结果是和样例输入中的是对应的,因此,你可以使用样例的输入输出简单的检查你的程序。
要特别指出的是,能够通过样例输入输出的程序并不一定是正确的程序,在测试的时候,会用很多组数据进行测试,而不局限于样例数据。有可能一个程序通过了样例数据,但测试的
时候仍只能得0分,可能因为这个程序只在一些类似样例的特例中正确,而不具有通用性,再测试更多数据时会出现错误。
比如,对于本题,如果你写一个程序不管输入是什么都输入57,则样例数据是对的,但是测试其他数据,哪怕输入是1和2,这个程序也输出57,则对于其他数据这个程序都不正确。
数据规模与约定
-10000 <= A, B <= 10000。
说明:“数据规模与约定”中给出了试题中主要参数的范围。
这个范围对于解题非常重要,不同的数据范围会导致试题需要使用不同的解法来解决。比如本题中给的A、B范围不大,可以使用整型(int)来保存,如果范围更大,超过int的范围,则要考虑其他方法来保存大数。
有一些范围在方便的时候是在“问题描述”中直接给的,所以在做题时不仅要看这个范围,还要注意问题描述。
参考程序
#include<stdio.h> #include<stdlib.h> int main() { int a,b; scanf("%d%d",&a,&b); printf("%d ",a+b); return 0; }
基础练习
《1》 闰年判断
问题描述
给定一个年份,判断这一年是不是闰年。 当以下情况之一满足时,这一年是闰年: 1. 年份是4的倍数而不是100的倍数; 2. 年份是400的倍数。 其他的年份都不是闰年。
输入格式
输入包含一个整数y,表示当前的年份。
输出格式
输出一行,如果给定的年份是闰年,则输出yes,否则输出no。
说明:当试题指定你输出一个字符串作为结果(比如本题的yes或者no,你需要严格按照试题中给定的大小写,写错大小写将不得分。
样例输入
2013
样例输出
no
样例输入
2016
样例输出
yes
数据规模与约定
1990 <= y <= 2050。
心得体会:闰年的判断条件经常会在其他地方用到,并且题目是不会给出提示的,所以应该熟记闰年的判断条件。
参考代码
#include<stdio.h> #include<stdlib.h> int main() { int year; scanf("%d",&year); if( ( year%4 == 0 && year%100 !=0 ) || year%400==0 ) { printf("yes"); } else { printf("no"); } return 0; }
《2》 01字串
问题描述
对于长度为5位的一个01串,每一位都可能是0或1,一共有32种可能。它们的前几个是:
00000
00001
00010
00011
00100
请按从小到大的顺序输出这32种01串。
输入格式
本试题没有输入。
输出格式
输出32行,按从小到大的顺序每行一个长度为5的01串。
样例输出
00000
00001
00010
00011
<以下部分省略>
题目分析
其实根据题目的意思可以知道,是要将十进制的0-31从小到大以二进制的形式输出。所以可以按从小到大的顺序将0-31转化成二进制输出。
当然这题也可以用5重嵌套循环实现。
参考代码
#include<stdio.h> #include<stdlib.h> int main() { int num = 31; int binary[5]; int i,j,k; for(i=0; i<=num; i++) { k=i; for( j=0; j<5; j++) { binary[j]=k%2; k = k/2; } for( j=4; j>=0; j--)//反向输出 { printf("%d",binary[j]); } printf(" "); } return 0; }
《3》字母图形
问题描述
利用字母可以组成一些美丽的图形,下面给出了一个例子:
ABCDEFG
BABCDEF
CBABCDE
DCBABCD
EDCBABC
这是一个5行7列的图形,请找出这个图形的规律,并输出一个n行m列的图形。
输入格式
输入一行,包含两个整数n和m,分别表示你要输出的图形的行数的列数。
输出格式
输出n行,每个m个字符,为你的图形。
样例输入
5 7
样例输出
ABCDEFG
BABCDEF
CBABCDE
DCBABCD
EDCBABC
数据规模与约定
1 <= n, m <= 26。
参考代码(做图形打印的题目要善于发现图形的分布规律,按照分析的规律准确输出图形即可)
#include<stdio.h> #include<stdlib.h> #define M 26 char graph[M][M]; int main() { int n,m; char c1='A',c2; scanf("%d%d",&n,&m); int i,j; for(i=0;i<n;i++) {
//打印一行字符 graph[i][i]=c1;//A for(c2=c1+1,j=i-1;j>=0;j--,c2++)graph[i][j]=c2;//A前面的字符 for(c2=c1+1,j=i+1;j<m;j++,c2++)graph[i][j]=c2;//A后面的字符 } for(i=0;i<n;i++) { for(j=0;j<m;j++)printf("%c",graph[i][j]); printf(" "); } return 0; }
《4》 数列特征
问题描述
给出n个数,找出这n个数的最大值,最小值,和。
输入格式
第一行为整数n,表示数的个数。
第二行有n个数,为给定的n个数,每个数的绝对值都小于10000。
输出格式
输出三行,每行一个整数。第一行表示这些数中的最大值,第二行表示这些数中的最小值,第三行表示这些数的和。
样例输入
5
1 3 -2 4 5
样例输出
5
-2
3
数据规模与约定
1 <= n <= 10000。
参考代码
#include<stdio.h> #include<stdlib.h> int main() { int n,i,a; scanf("%d",&n); int num[n]; for( i=0; i<n; i++) { scanf("%d",&num[i]); } int min = num[0];//min和max的值还可以通过调用函数min()和max()求得 int max = num[0]; int sum = num[0]; for( i=1; i<n; i++) { sum = sum + num[i]; if( num[i] > max) { max = num[i]; } if( num[i] < min) { min = num[i]; } } printf("%d %d %d ",max,min,sum); return 0; }
《5》查找整数
问题描述
给出一个包含n个整数的数列,问整数a在数列中的第一次出现是第几个。
输入格式
第一行包含一个整数n。
第二行包含n个非负整数,为给定的数列,数列中的每个数都不大于10000。
第三行包含一个整数a,为待查找的数。
输出格式
如果a在数列中出现了,输出它第一次出现的位置(位置从1开始编号),否则输出-1。
样例输入
6
1 9 4 8 3 9
9
样例输出
2
数据规模与约定
1 <= n <= 1000。
心得体会
熟练运用C++中<algoritm>所提供的函数可以减少自己编写相应代码的时间。
参考代码
//调用<algorithm>中的find函数进行查找 #include<stdio.h> #include<stdlib.h> #include<algorithm> using namespace std; int main() { int n,a; scanf("%d",&n); int num[n],i; for(i=0;i<n;i++)scanf("%d",&num[i]); scanf("%d",&a); int *resul=find(num,num+n,a);//find(start,end,num_to_find);若找到这result指向查找值的位置,找不到的话会返回一个“逾尾”的迭代器 printf("%d",resul-num+1); return 0; } //自己编写查找代码 #include<stdio.h> #include<stdlib.h> int main() { int count,find; scanf("%d",&count); int num[count]; int i; for( i=0; i<count; i++) { scanf("%d",&num[i]); } scanf("%d",&find); int k=-1; for( i=0; i<count; i++) { if( num[i] == find ) { k=i+1; break; } } printf("%d",k); return 0; }
《6》杨辉三角形
问题描述
杨辉三角形又称Pascal三角形,它的第i+1行是(a+b)i的展开式的系数。
它的一个重要性质是:三角形中的每个数字等于它两肩上的数字相加。
下面给出了杨辉三角形的前4行:
1
1 1
1 2 1
1 3 3 1
给出n,输出它的前n行。
输入格式
输入包含一个数n。
输出格式
输出杨辉三角形的前n行。每一行从这一行的第一个数开始依次输出,中间使用一个空格分隔。请不要在前面输出多余的空格。
样例输入
4
样例输出
1
1 1
1 2 1
1 3 3 1
数据规模与约定
1 <= n <= 34。
参考代码(此题为图形打印题,只要掌握了图形的变化规律,按照规律输出即可)
#include<stdio.h> #include<stdlib.h> #define MAXSIZE 34 int main() { int n,i,j,num[MAXSIZE][MAXSIZE]; scanf("%d",&n); num[0][0] = 1; printf("%d ",num[0][0]); for( i=1; i<n; i++) { num[i][0] = 1; printf("%d ",num[i][0]); for( j=1; j<=i-1; j++) { num[i][j] = num[i-1][j-1]+num[i-1][j]; printf("%d ",num[i][j]); } num[i][i] = 1; printf("%d ",num[i][i]); } return 0; }
《7》特殊的数字
问题描述
153是一个非常特殊的数,它等于它的每位数字的立方和,即153=1*1*1+5*5*5+3*3*3。编程求所有满足这种条件的三位十进制数。
输出格式
按从小到大的顺序输出满足条件的三位十进制数,每个数占一行。
分析
本题是要求三位数的水仙花数,既从100-999间的水仙花数,可以利用三重嵌套实现,既可另i,j,k分别代表百位、十位、个位。也可以写一个判断水仙花数的函数,这个函数将一个整数拆分为单个数字,然后判断。
参考程序
#include<stdio.h> #include<stdlib.h> #define MAXNUM 1000 #define MINNUM 100 int isflower(int num) { int sum = 0; int k = num; int i; while( k ) { i = k % 10; sum += i*i*i; k = k/10; } if( num == sum ) { return 1; } else { return 0; } } int main() { int i; for ( i=MINNUM; i<MAXNUM ; i++) { if ( isflower(i)) { printf("%d ",i); } } return 0; }
《8》 回文数
问题描述
1221是一个非常特殊的数,它从左边读和从右边读是一样的,编程求所有这样的四位十进制数。
输出格式
按从小到大的顺序输出满足条件的四位十进制数。
分析
此题可以用四重嵌套循环实现,i,j,k,m表示从百位到十位的数字,当i==m&&j==k的时候数字满足要求。当然也可以另写一个判断函数,将整形参数拆分后再进行判断。
参考代码
//嵌套循环代码 #include<stdio.h> int main() { int i,j,k,m; for(i=1;i<10;i++) { for(j=0;j<10;j++) { for(k=0;k<10;k++) { for(m=0;m<10;m++) { if(i==m&&j==k) { printf("%d ",i*1000+j*100+k*10+m); } } } } } return 0; }
//写一个判断函数的代码 #include<stdio.h> #include<stdlib.h> #define MAXNUM 10000 #define MINNUM 1000 #define COUNT 4 int isbacknum( int num ) { int a[COUNT],i; for ( i=COUNT-1; i>=0; i--) { a[i] = num % 10; num = num/10; } if( a[0]==a[3] && a[1]==a[2]) { return 1; } else { return 0; } } int main() { int i; for( i=MINNUM; i<MAXNUM; i++) { if ( isbacknum(i)) { printf("%d ",i); } } return 0; }
《9》特殊回文数
问题描述
123321是一个非常特殊的数,它从左边读和从右边读是一样的。
输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n 。
输入格式
输入一行,包含一个正整数n。
输出格式
按从小到大的顺序输出满足条件的整数,每个整数占一行。
样例输入
52
样例输出
899998
989989
998899
数据规模和约定
1<=n<=54。
分析
解题方法跟上一题类似,只是多了一个限制条件,也就是各个位数加起来的和等于n
参考代码
//嵌套循环实现 #include <iostream> using namespace std; int main() { int n,a,b,c,t; cin>>n; for(a=1;a<10;a++)//5位数的情况 for(b=0;b<10;b++) for(c=0;c<10;c++) { t=a*10001+b*1010+c*100; if(2*a+2*b+c==n) cout<<t<<endl; } for(a=1;a<10;a++)//6位数的情况 for(b=0;b<10;b++) for(c=0;c<10;c++) { t=a*100001+b*10010+c*1100; if(2*a+2*b+2*c==n) cout<<t<<endl; } return 0; }
//利用判断函数 #include<stdio.h> #include<stdlib.h> #include<math.h> #define MAXNUM 1000000 #define MINNUM 10000 int isbacknum(int num, int n) { int sum = 0; int a[7]; int i = 1; while( num ) { a[i] = num % 10; sum += a[i]; num = num / 10; i++; } i--; int j; int k = floor(i/2); for ( j=1; j<=k ; j++) { if( a[j] != a[i-j+1] ) { break; } } if( j>k && sum == n) { return 1; } else { return 0; } } int main() { int i,n; scanf("%d",&n); for ( i=MINNUM; i<MAXNUM; i++) { if (isbacknum(i,n)) { printf("%d ",i); } } return 0; }
《10》 十进制转十六进制
问题描述
十六进制数是在程序设计时经常要使用到的一种整数的表示方式。它有0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F共16个符号,分别表示十进制数的0至15。十六进制的计数方法是满16进1,所以十进制数16在十六进制中是10,而十进制的17在十六进制中是11,以此类推,十进制的30在十六进制中是1E。
给出一个非负整数,将它表示成十六进制的形式。
输入格式
输入包含一个非负整数a,表示要转换的数。0<=a<=2147483647
输出格式
输出这个整数的16进制表示
样例输入
30
样例输出
1E
分析
十进制转换成十六进制,可以采用除以十六取余法。并且将10-15换成相应的字母即可。此处需要注意边界值的处理。此外还可以借助转换数组解决这个问题。
参看代码
#include<stdio.h> #include<stdlib.h> int main() { long long a; int b,i; char c[11]; scanf("%I64d",&a); i=0; if( 0 == a)//这里一定不能漏了 { printf("%d",0); } else { while (a) { b = a%16; if ( b<10 ) { c[i] = 48 + b; } else { c[i] = 48 + b + 7; } i++; a = a/16; } int j; for ( j=i-1; j>=0; j--)//反向输出 { printf("%c",c[j]); } } return 0; }
//借用辅助数组 #include <stdio.h> #include <stdlib.h> char data[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; //输出 void Print(char *num,int n) { int i; for(i=n-1;i>=0;i--) printf("%c",num[i]); printf(" "); printf(" "); } //将十六进制数转换为十进制数 int Transform(char *num,long long value) { int n=0; while(value>=16) { num[n++]=data[value%16]; value/=16; } num[n++]=data[value%16]; return n; } int main() { long long value; char num[10]; int n; scanf("%I64d",&value); n=Transform(num,value); Print(num,n); return 0; }
《11》十六进制转十进制
问题描述
从键盘输入一个不超过8位的正的十六进制数字符串,将它转换为正的十进制数后输出。
注:十六进制数中的10~15分别用大写的英文字母A、B、C、D、E、F表示。
样例输入
FFFF
样例输出
65535
分析
此题是上一题的逆过程,只要将A-F和十进制的10-15对应起来,假设an为第n位十六进制数,则十进制数D=an*16^(n-1)+a(n-1)*16^(n-1)+...+a1.
参考代码
#include<stdio.h> #include<stdlib.h> #include<string.h> int main() { char data[9]; int i; scanf("%s",data); int len=strlen(data); long long step = 1; long long sum =0; for (i=len-1; i>=0; i--) { if( data[i] <= '9' ) { sum += (data[i]-'0')*step; } else { sum += (data[i]-'A'+10)*step; } step *=16; } printf("%I64d",sum); return 0; }
《12》 十六进制转八进制
问题描述
给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
输入的第一行为一个正整数n (1<=n<=10)。
接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
输出格式
输出n行,每行为输入对应的八进制正整数。
注意
输入的十六进制数不会有前导0,比如012A。
输出的八进制数也不能有前导0。
样例输入
2
39
123ABC
样例输出
71
4435274
提示
先将十六进制数转换成某进制数,再由某进制数转换成八进制。
分析
题目说明十六进制的长度在100000,以内。若将十六进制先转换为十进制的话,这个经过转换后得到的十进制必定无法存储。所以此处应该以二进制数为中间转换进制,4位二进制可以标识一位十六进制数,3位二进制可以表示一位8进制数。转换成八进制后再去掉前导码即可。
参考代码
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #define MAXSIZE 100001 void hex2binary( char* hex,char* binary ) { int hex_n = strlen(hex); int value; int i; int k=0; for ( i=0 ; i<hex_n; i++ ) { if ( hex[i] <= '9') { value = hex[i]-'0'; } else { value = hex[i] -'A' +10; } int j; int c=k; for (j=c+3; j>=c; j--) { binary[j] = value % 2 + '0'; value = value / 2; k++; } } binary[k] = ' '; } void binary2octal ( char* binary, char* octal) { int binary_n = strlen(binary); int i,j=0; int k = binary_n % 3; if( 2==k ) { octal[0] = (binary[0]-'0')*2+binary[1]; j=1; } else if ( 1==k ) { octal[0] = binary[0]; j=1; } int count = strlen(binary); for ( i=k; i<count; i+=3) { octal[j] = (binary[i]-'0')*2*2 + (binary[i+1]-'0')*2 + (binary[i+2]-'0') + '0'; j++; } octal[j] = ' '; } void display(char *data) { int i=0; int n = strlen(data); int k = 0; while(data[k]=='0') { k++; } if( k==n) { printf("%d",0); } else{ for (i=k; i<n; i++) { printf("%c",data[i]); } } printf(" "); } int main() { char hex[11][MAXSIZE]; char binary[MAXSIZE*4]; char octal[MAXSIZE*3]; int n,i; scanf("%d",&n); getchar(); for (i=0; i<n; i++) { scanf("%s",hex[i]); } for( i=0; i<n; i++) { hex2binary(hex[i],binary); binary2octal(binary,octal); display(octal); } return 0; }
《13》数列排序
问题描述
给定一个长度为n的数列,将这个数列按从小到大的顺序排列。1<=n<=200
输入格式
第一行为一个整数n。
第二行包含n个整数,为待排序的数,每个整数的绝对值小于10000。
输出格式
输出一行,按从小到大的顺序输出排序后的数列。
样例输入
5
8 3 6 4 9
样例输出
3 4 6 8 9
参考代码
//选择排序 #include<stdio.h> #include<stdlib.h> int main() { int n,data[201]; scanf("%d",&n); int i; for( i=0; i<n; i++) { scanf("%d",&data[i]); } int j,temp; for (i=0; i<n; i++) { for( j=i+1; j<n; j++) { if(data[j]<data[i]) { temp = data[j]; data[j] = data[i]; data[i] =temp; } } } for (i=0; i<n; i++) { printf("%d ",data[i]); } return 0; }
//调用sort排序函数 #include<stdio.h> #include<stdlib.h> #include<algorithm> using namespace std; int a[210]; int main() { int n; scanf("%d",&n); int i; for(i=0;i<n;i++)scanf("%d",&a[i]); sort(a,a+n); for(i=0;i<n;i++)printf("%d ",a[i]); printf(" "); return 0; }