信息学奥赛初赛天天练-61-NOIP2018普及组-完善程序1-约数、公约数、最大公约数、模运算、辗转相除法、欧几里得算法

PDF文档公众号回复关键字:20240810

1 完善程序 (单选题 ,每小题3分,共30分)

最大公约数之和

下列程序想要求解整数 n的所有约数两两之间最大公约数的和对 10007 求余后的值,试补全程序。(第一空 2 分,其余 3 分)

举例来说,4 的所有约数是 1,2,4。1 和 2 的最大公约数为 1;2 和 4 的最大公约数为 2;1 和 4 的最大公约数为 1 。于是答案为 1+2+1=4。

要求 getDivisor 函数的复杂度为O(sqrt(n)), gcd 函数的复杂度为O(log max(a,b))

01 #include <iostream>
02 using namespace std;
03 
04 const int N = 110000, P = 10007;
05 int n;
06 int a[N], len;
07 int ans;
08 
09 void getDivisor() {
10     len = 0;
11     for (int i = 1; ① <= n; ++i)
12         if (n % i == 0) {
13           a[++len] = i;
14           if ( ② != i) a[++len] = n / i;
15         }
16 }
17 
18 int gcd(int a, int b) {
19     if (b == 0) {
20     	③ ;
21     }
22     return gcd(b, ④ );
23 }
24 
25 int main() {
26     cin >> n;
27     getDivisor();
28     ans = 0;
29     for (int i = 1; i <= len; ++i) {
30         for (int j = i + 1; j <= len; ++j) {
31         	ans = ( ⑤ ) % P;
32         }
33     }
34     cout << ans << endl;
35     return 0;
36 }

1 ①处应填( )

2 ②处应填( )

3 ③处应填( )

4 ④处应填( )

5 ⑤处应填( )

2 相关知识点

因数 -约数

如果 d|a 且 d>=0 则称d是a的因数 ,因数也可以被称为约数

例如

2|8 ,则称2是8的因数,或者称2是8的约数

公约数

如果数p同时是两个数a,b的约数,我们就称p为a和b的公约数

即 p|a , p|b 则p是a和b的公约数

例如

2|4 ,2|6 则2是4和6的公约数

最大公约数

a和b的所有公约数中最大的那个数称为a和b的最大公约数

24的约数

1 2 3 4 6 8 12 24

18的约数

1 2 3 6 9 18

18和24的公约数

1 2 3 6

公约数最大的是6,所以6是18和24的最大公约数

辗转相除法 - 欧几里得算法

用一个数除以另一个数,如果余数不为 0,则用除数除以余数,一直反复,直到余数为 0 为止

把两个数看作被除数与除数的关系,则两个数的最大公约数就等于除数与余数的最大公约数

r=a%b  
gcd(a,b) = gcd(b,r)

参考程序

#include<bits/stdc++.h>
using namespace std;
int a,b;

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

int main(){
	scanf("%d%d", &a, &b);
	int c=gcd(a,b);
	printf("最大公约数是 %d",c);
	return 0;
}
/*
输入 
4 6
输出
2 
*/

模运算

模运算,就是取余数,在计算机语言中用%来表示。举个简单的例子,3 % 5 = 3。结果的取值范围在 0 与模之间

例如

c=x/y

c=3 mod 5 =3 c的取值范围 [0,y-1]

结果也可以用负数表示,即 c=-2

3 思路分析

求n的约数

任何一个数n都是有2个约数相乘的乘积

例如

10=1*10

10=2*5

4=1*4

4=2*2

所以在枚举时,只要枚举前半部分约数即可,后1个约数可以使用n/i获得

4可以枚举1 ,然后通过4/1=4计算出后面一个约数

枚举2,可以通过4/2=2计算出后面一个约数

11     for (int i = 1; ① <= n; ++i)
12         if (n % i == 0) {
13           a[++len] = i;
14           if ( ② != i) a[++len] = n / i;
15         }

枚举所有约数

i从1开始,j从i+1开始枚举可以避免重复,后面1个数一定比前面数大

例如

4有3个约数,分别是1,2,4

1和2求最大公约数

1和4求最大公约数

2和4求最大公约数

避免再求2和1,4和1,4和2的最大公约数,这些是前面是重复的

29     for (int i = 1; i <= len; ++i) {
30         for (int j = i + 1; j <= len; ++j) {
31         	ans = ( ⑤ ) % P;
32         }
33     }

求2个数的最大公约数

参考辗转相除法

1 ①处应填( i*i )

分析

任何一个数n都是有2个约数相乘的乘积
例如
10=1*10
10=2*5
4=1*4
4=2*2
所以在枚举时,只要枚举前半部分约数即可,后1个约数可以使用n/i获得
4可以枚举1 ,然后通过4/1=4计算出后面一个约数
枚举2,可以通过4/2=2计算出后面一个约数
11     for (int i = 1; ① <= n; ++i)
12         if (n % i == 0) {
13           a[++len] = i;
14           if ( ② != i) a[++len] = n / i;
15         }

2 ②处应填( n/i )

分析

根据第1题,任何一个数n都是有2个约数相乘的乘积
枚举1个约数,如果存在约数,会有2个约数,i和n/i
所以应该数组中存放2个约数,如果这个数是平方根除外
例如
n=4 i=2时,n/i也是2,此时2已经存放到数组了,不在存放
除此情况,n/i都要添加到数组
11     for (int i = 1; ① <= n; ++i)
12         if (n % i == 0) {
13           a[++len] = i;
14           if ( ② != i) a[++len] = n / i;
15         }

3 ③处应填( return a )

分析

根据辗转相除法,两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数,一直反复,直到余数为 0 为止
如果余数为0了,a为最大公约数
19     if (b == 0) {
20     	③ ;
21     }

4 ④处应填( a%b )

分析

根据辗转相除法,两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数
所以填两数相除余数,a%b
22     return gcd(b, ④ );

5 ⑤处应填( ans + gcd(a[i], a[j])

分析

逐一枚举2个数的最大公约数并累加到ans
2个数a[i],a[j]的最大公约数,gcd(a[i], a[j])
累加到ans为ans+gcd(a[i], a[j])
28     ans = 0;
29     for (int i = 1; i <= len; ++i) {
30         for (int j = i + 1; j <= len; ++j) {
31         	ans = ( ⑤ ) % P;
32         }
33     }
posted @ 2024-08-10 21:15  new-code  阅读(8)  评论(0编辑  收藏  举报