2019年10月25日作业题解

前几道题都是Special Judge只需要提交答案和头文件就行了,这一点OJ上首页有自己看一下就好了
直接进正文
A题编写函数:判断闰年 (Append Code)

Description
输入一个正整数的年份,判断是否为闰年。
编写一个函数用于判断闰年。
用C语言实现:append.c中函数原型为
int is_leap_year(int year);
功能:若参数year是闰年返回1,否则返回0。
用C++实现:append.cc中函数原型为
bool isLeapYear(int year);
功能:若参数year是闰年返回true,否则返回false。
函数的调用格式见“Append Code”。
Input
输入只有一行,为一个10000以内的正整数。
Output
输出为一行。
若输入为闰年偶数则输出“Yes”,否则输出“No”。
Sample Input
2010
Sample Output
No
标程
提交内容

#include<stdio.h>

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

主函数

int main()
{
    int year;
    
    scanf("%d", &year);
    is_leap_year(year) ? printf("Yes") : printf("No");
    
    return 0;
}

完整代码

#include<stdio.h>

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

int main()
{
    int year;
    
    scanf("%d", &year);
    is_leap_year(year) ? printf("Yes") : printf("No");
    
    return 0;
}

这道题的关键在于找满足函数闰年的条件
闰年的条件不知是四年一闰
闰年判断的标准:1.能整除4且不能整除100 2.能整除400
看一下产生闰年的条件

严格上讲,"每4年一个闰年"这说法不严谨。应该是四年一闰,百年不闰,四百年再闰。
为什么呢?
1、产生闰年原因:地球绕太阳运行周期为365天5小时48分46秒(合365.24219天)即一回归年(tropical year)。公历的平年只有365日,比回归年短约0.2422 日,所余下的时间约为四年累计一天,故四年于2月加1天,使当年的历年长度为366日,这一年就为闰年。
2、但是,上面算法又有了一个问题。就是0.2422*4=0.9688,比一天还差0.0322天,每4年差0.0322天不算多,但每400年就会差了约3天。即是说,假如每4年一个闰年,那么每400年就会有100个闰年,然后会多算了3天。
所以,就规定了每四百年中要减少三个闰年。公历年份是整百数的,必须是400的倍数的才是闰年,不是400的倍数的,虽然是100的倍数,也是平年。
——摘自百度

这个记住就好了,就是可以整除4但不整除100或者可以整除400
程序的话就很好写了

B题编写函数:求最大公约数gcd()和最小公倍数lcm() (Append Code)

Description
辗转相除法,也称欧几里得算法,是求最大公约数的算法。辗转相除法首次出现于欧几里得的《几何原本》(第VII卷,命题i和ii)中,而在中国则可以追溯至东汉出现的《九章算术》。
两个整数的最大公约数(亦称公约数)是能够同时整除它们的最大的正整数。辗转相除法基于如下原理:两个整数的最大公约数等于其中较小的数和两数的差的最大公约数。例如,252和105的最大公约数是21(252 = 21 × 12;105 = 21 × 5);因为252 − 105 = 147,所以147和105的最大公约数也是21。在这个过程中,较大的数缩小了,所以继续进行同样的计算可以不断缩小这两个数直至其中一个变成零。这时,所剩下的还没有变成零的数就是两数的最大公约数。
例如,计算a = 1071和b = 462的最大公约数的过程如下:从1071中不断减去462直到小于462(可以减2次,即商q0 = 2),余数是147:
1071 = 2 × 462 + 147.
然后从462中不断减去147直到小于147(可以减3次,即q1 = 3),余数是21:
462 = 3 × 147 + 21.
再从147中不断减去21直到小于21(可以减7次,即q2 = 7),没有余数:
147 = 7 × 21 + 0.
此时,余数是0,所以1071和462的最大公约数是21。

要求编写两个函数:

  1. 求最大公约数的函数gcd()。gcd()的返回值是两个参数的最大公约数,函数原型如下:
    int gcd(int, int);
  2. 求最小公倍数的函数lcm()。lcm()的返回值是两个参数的最小公倍数,函数原型如下:
    int lcm(int, int);
    函数gcd()和lcm()的调用格式见“Append Code”。
    Input
    输入为多行,每行有一对非负整数a,b,且a*b不会超出int类型的数据范围。输入至EOF结束。
    Output
    每行输出一对a,b的最大公约数和最小公倍数,顺序与输入对应。
    从整除定义出发:若a整除b(b除以a没有余数),则b是a的倍数,a是b的约数,这里要求b不为0。因此0是任意整数的倍数(任意整数都是0的约数),但是0不能是约数。
    Sample Input
    1 1
    2 3
    2 2
    3 2
    4 6
    7 5
    12 6
    18 9
    24 36
    Sample Output
    1 1
    1 6
    2 2
    1 6
    2 12
    1 35
    6 12
    9 18
    12 72
    标程
    提交内容
#include<stdio.h>

int gcd(int a, int b){
	if(b==0){
		return a;
	}
	else{
		return gcd(b, a%b);
	}	
}
int lcm(int a, int b){
	return a*b/gcd(a,b);
}

主函数

int main()
{
    int a, b;
    while(scanf("%d %d", &a, &b) != EOF)
        printf("%d %d\n", gcd(a, b), lcm(a, b));
    return 0;
}

完整代码

#include<stdio.h>

int gcd(int a, int b){
	if(b==0){
		return a;
	}
	else{
		return gcd(b, a%b);
	}	
}
int lcm(int a, int b){
	return a*b/gcd(a,b);
}

int main()
{
    int a, b;
    while(scanf("%d %d", &a, &b) != EOF)
        printf("%d %d\n", gcd(a, b), lcm(a, b));
    return 0;
}

有必要简单介绍一下最大公约数和最小公倍数
最大公约数和最小公倍数是oi和acm中很常见的两个数论基本知识
原来集训的时候就见过很难的gcd(守护gcd!!!)的数论题,gcd经常在题目中出现
GCD又名XXX
是最大公约数的意思
最大公因数,也就是最大公约数,指的是两个或多个整数共有约数中最大的一个。
常用的求最大公约数的方法是辗转相除法(扩展欧几里得算法)
方法就是:

  1. 较小数除较大数
  2. 用出现的余数去除除数
  3. 再用出现的余数去除第一余数
  4. 直到最后余数是0为止
  5. 如果是求两个数的最大公约数,那么最后的除数就是这两个数的最大公约数
    举个栗子:
    a=123456 b=7890
  a                        b                            a mod b
  123456                   7890                         5106
  7890                     5106                         2784
  5106                     2784                         2322
  2784                     2322                         462
  2322                     462                          12
  462                      12                           6
  12                       6                            0

此时最后的b就是结果即最后的最大公约数
最大公约数的求法主要有两种

1.递归法

也就是我做的方法

int gcd(int a, int b){
	if(b==0){
		return a;
	}
	else{
		return gcd(b, a%b);
	}	
}

或者

int gcd(int a, int b){
	if(a%b==0){
		return b;
	}
	else{
		return gcd(b, a%b);
	}	
}

这是递归法的两种形式

2.非递归法

int gcd(int a,int b){
	while(a%b!=0){
		int k=a;
		a=b,b=k%b;
	}
	return b;
}

非递归法就是用一个while循环就可以了

最小公倍数LCM
两个或多个整数公有的倍数叫做它们的公倍数,其中除0以外最小的一个公倍数就叫做这几个整数的最小公倍数。
有一个结论:最小公倍数与最大公约数的乘积是a和b的乘积
具体不在这里证明
LCM用的频率不如GCD但是也算是常用的函数之一

int lcm(int a, int b){
	return a*b/gcd(a,b);
}

C题编写函数:素数的判定 (Append Code)

同样是一道Special Judge的题目
Description
一个正整数n是素数:除了1和n不能被其他数整除。1不是素数。
编写一个函数用于判定一个正整数是不是素数。
用C语言实现:append.c中函数原型为
int is_primer(int num);
功能:若num为素数返回1,否则返回0。
用C++实现:append.cc中函数原型为
bool isPrimer(int num);
功能:若num为素数返回true,否则返回false。
函数的调用格式见“Append Code”。
Input
每行输入一个正整数n。
n不会超出int类型数据范围。
输入最多不超过20个正整数。
Output
若n为素数,输出“YES”,否则输出“NO”。
Sample Input
1
2
3
4
5
6
7
8
9
2147483647
Sample Output
NO
YES
YES
NO
YES
NO
YES
NO
NO
YES
HINT
如果你是按照从小到大的顺序选择除数去判定一个数,那么你超时的原因多半是用了太多不必要的除数。程序需要优化,减少循环的次数。
标程
提交部分

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

int is_primer(int num){
    int i,j=0;
    if(num==1){
    	return 0;
	}
    else{
        for(i=sqrt(num);i>1;i--){
            if(num%i==0){
                j++;
                return 0;
            }
        }
        if(j==0){
        	return 1;
		} 
    }
}

主函数

int main()
{
    int num;
    while(scanf("%d", &num) != EOF)
    {
        if(is_primer(num))
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

int is_primer(int num){
    int i,j=0;
    if(num==1){
    	return 0;
	}
    else{
        for(i=sqrt(num);i>1;i--){
            if(num%i==0){
                j++;
                return 0;
            }
        }
        if(j==0){
        	return 1;
		} 
    }
}
int main()
{
    int num;
    while(scanf("%d", &num) != EOF)
    {
        if(is_primer(num))
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}

如果挨个判断会让程序TLE(提示有提示,但是题目给的时间限制是3s这一点很不厚道),怎么来降低时间复杂度呢?最简单的方法是减少循环次数,所以内层循环改成sqrt(n)即可
还有其他降低时间复杂度的比如氧气优化,臭氧优化,卡常数,在这里先不讲了

D题编写函数:求累加和 (Append Code)

Description
给出两整数min和max,求min到max之间的数的累加和。
编写一个函数add()。函数原型为
int add(int n);
功能:每次调用都把参数n的值累加起来,并返回。
函数add()的调用格式见“Append Code”。
Input
输入为两个整数min和max,且max>=min。
Output
min和max之间所有整数的累加和,包括min和max。
Sample Input
1 10
Sample Output
55
标程

#include<stdio.h>

int sum;

int add(int n){
	sum+=n;
	return sum;
}

int main()
{
    int min, max, sum;    
    scanf("%d%d", &min, &max);    
    while(min <= max)
        sum = add(min++);        
    printf("%d", sum);    
    return 0;
}

全局变量那么好用为什么不用全局呢

E题编写函数:各位数字之和 (Append Code)

Description
给定一个正整数,求它的各位数字之和,直到这个和只有一位数为止。
例如,给出整数1236,那么计算
1+2+3+6=12
因为12是一个两位数,所以继续求和
1+2=3
得到结果为:3。
编写一个函数digit_sum()完成求和的功能:
原型:int digit_sum(int num);
功能:返回整数num的各个位数字之和。
函数的调用格式见“Append Code”。
Input
一个int类型的正整数N。
Output
N的各位数字之和,并不断求和,直到所求的和只有一位数字为止。
Sample Input
1236
Sample Output
3
标程

#include<stdio.h>

int digit_sum(int num){
	int s=0;
	while(num!=0){
		s+=num%10;
		num=num/10;
	}
	if(s>=10){
		s=digit_sum(s);
	}
	return s;
}


int main()
{
    int n;
    scanf("%d", &n);
    printf("%d", digit_sum(n));
    return 0;
}

取各位使用递归求和即可

F题Print Graphics Problerm (I)

Description
向标准输出上打印一些用ASCII字符组成的图形。
Input
输入为一个整数n,0<n<100。
Output
输出一个n层等腰三角形,格式见sample。
Sample Input
5
Sample Output
+
+++
+++++
+++++++
+++++++++

标程

#include<stdio.h>

int main(){
    int i,j,k,n;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        for(j=1;j<=n-i;j++){
        	printf(" ");
		} 
        for(k=1;k<=i+i-1;k++){
        	printf("+");
		}
        printf("\n");
    }
    return 0;
}
 

G题

Description
向标准输出上打印一些用ASCII字符组成的图形。
Input
输入为多个整数n,0<n<100。当n为0时结束输入。
Output
若n为偶数,则输出一个正向的n层等腰三角形;n为奇数,则输出一个倒向的n层等腰三角形。三角形由“+”组成。任意两个图形之间有一个空行分隔,格式见sample。
Sample Input
5
4
0
Sample Output
+++++++++
+++++++
+++++
+++
+

+++
+++++
+++++++
标程

#include<stdio.h>

int main(){
    int a,b,c,n,i;
    while(scanf("%d",&n)!=EOF){
        if(n%2==0){
            for(i=1;i<=n;i++){
                for(a=1; a<=n-i; a++){
                	printf(" ");
				}
                for(b=1; b<=i+i-1; b++){
                	printf("+");
				} 
                printf("\n");
            }
            printf("\n");
        }
        if(n%2!=0){
            for(i=1; i<=n; i++){
                for(a=1; a<i; a++){
                	printf(" ");
				}   
                for(b=(n-i)*2+1; b>0; b--){
                	printf("+");
				}
                printf("\n");
            }
        	printf("\n");
        }
        if (n==0) break;
    }
    return 0;
}
 

H题Print Graphics Problerm (III) (Append Code)

Description
向标准输出上打印一些用ASCII字符组成的图形。
编写一个函数用于输出ASCII图形。
用C语言实现:append.c中函数原型为
int print_graphic(int n, char c);
用C++实现:append.cc中函数原型为
int printGraphic(int n, char c);
功能:输出n层有字符c组成的图形。
函数的调用格式见“Append Code”。
Input
输入为一个整数n和一个字符c,0<n<100。
Output
输出一个n层等腰三角形,由字符c组成,格式见sample。
Sample Input
5 *
Sample Output
*





标程

#include<stdio.h>

int print_graphic(int num,int c){
	int i,j;
	for(i=1;i<=num;++i){
		for(j=1;j<=num-i;++j){
			printf(" ");
		}
		for(j=1;j<=2*i-1;++j){
			putchar(c);
		}
		printf("\n");
	}
}

int main()
{
    char c;
    int num;
    scanf("%d %c", &num, &c);
    print_graphic(num, c);
    return 0;
}

这三道题几乎一样很简单,就是简单找一下规律就好
思路也给很简单

发布了41 篇原创文章 · 获赞 58 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/a1351937368/article/details/102749020
今日推荐