编程语言
首页 > 编程语言> > 蓝桥杯真题 2019第十一届 国赛JavaB组 #E 序列求和 详细题解

蓝桥杯真题 2019第十一届 国赛JavaB组 #E 序列求和 详细题解

作者:互联网

E 序列求和

本题总分:15 分


问题描述

学习了约数后,小明对于约数很好奇,他发现,给定一个正整数 t,总是可以找到含有 t 个约数的整数。小明对于含有 t 个约数的最小数非常感兴趣,并把它定义为 St 。
例如 S1 = 1, S2 = 2, S3 = 4, S4 = 6,· · · 。
现在小明想知道,前 60 个 Si 的和是多少?即 S1 + S2 + · · · + S60 是多少?


答案提交

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。







先说一下正确答案吧:292809912969717649

说点什么

网上有看到别人说有两种答案,其实说两种答案的都是错的,客观题只有一个答案,他们会说两种答案是因为他们没有理解好题意,题目说的是“总是可以找到含有 t 个约数的整数”,注意理解“t个”的意思,t个即刚好只能是t个,不能多,不能少。
下面说思路
思路有两种,一种是无脑暴搜,另一种则是用数学公式暴搜


无脑暴搜

先说一下无脑暴搜,这种思路都是很多人最先想到的,我也是。
但是最后发现很难行得通,懒得看这种行不通的思路的请跳到下面第二种思路的讲解

思路:遍历从1到某个很大的数n,在外层循环遍历到n时判断n有多少个因子t,
	即在内层循环里遍历1到根号n(本来应该再次遍历到n,优化一下,把范围缩小根号n
	(跟判断某个数是不是质数一个道理,这里不再赘述,不懂的百度)),
	内层循环遍历完后再更新用来记录答案的数组result[t]

下面代码
#include<stdio.h>
#include<iostream>
#pragma warning(disable:4996)
using namespace std;

bool vis[1000];
long result[1000];
int main(){
		int count = 1;
		for (long i = 1; i < 1000000; i++) {
			int temp = 0;
			for (int j = 1; j * j <= i; j++) {
				if (i % j == 0) {
					if (j * j == i) {
						temp++;
					} else {
						temp += 2;
					}
				}
			}
			if (vis[temp] == false) {
				vis[temp] = true;
				result[temp] = i;
				count++;
			}
		}
		for (int i = 1; i < 60; i++) {
			printf("%d ", result[i]);
			if (i % 10 == 0) {
				printf("\n");
			}
		}

		bool flag = false;
		printf("\n");
		for (int i = 1; i <= 60; i++) {
			if (vis[i] == false) {
				printf("%d ", i);
				flag = true;
			}
		}
		printf("\n%d", flag);
}

//1 2 4 6 16 12 64 24 36 48
//1024 60 4096 192 144 120 65536 180 262144 240
//576 3072 4194304 360 1296 12288 900 960 0 720
//0 840 9216 196608 5184 1260 0 786432 36864 1680
//0 2880 0 15360 3600 0 0 2520 46656 6480
//589824 61440 0 6300 82944 6720 2359296 0 0
//发现这几个位置的数一直找不到,即使第一个for循环的i已经达到int无法存储的地步:29 31 37 41 43 46 47 53 58 59
//而且随着i的量级的增加,计算耗时已经达到需要估计十几分钟的地步了,这种暴搜也没什么好优化的,只是小小优化,但耗时还是很长




数学公式暴搜

在讲这种思路前需要先跟大家讲一下这个数学公式:

唯一分解定理/算术基本定理
唯一分解定理又称为算数基本定理,基本内容是:

每个大于1的自然数,要么本身就是质数,要么可以写为2个或以上的质数的积,而且这些质因子按大小排列之后,写法仅有一种方式。

用另一种方法表示就是:

对于任何一个大于1的正整数,都存在一个标准的分解式: N=p1^a1 * p2a2*···*pnan;(其中一系列an为指数,pn为质数)

此定理表明:任何一个大于 1 的正整数都可以表示为素数的积。

有这样几个式子:

F(n)代表任意的正整数n的正因子的数量,则F(n)=(a1+1)(a2+1)(a3+1)······(an+1);

设G(n)代表n的正因子的和,则G(n)=(1+p12+p13+…+p1a1)*(1+p22+p23+…p2a2)(1+pn1+pn2+…+pn^an)=;

详细的这里不说太多,这里只要需要知道:
1.对于任何一个大于1的正整数都可以分解成若干个质数的积。
2.任意的正整数n的正因子数量t是有公式可求的

思路:
1.首先我们得知道我们需要求的是什么:含有 t 个约数的整数n,因题目需要总和最小,
所以这个n需要在所有含有t个约数的数中最小
2.而根据数学公式我们知道任意的正整数n的正因子的数量t=(a1+1)*(a2+1)*(a3+1)*······*(an+1);
3.由于n=p1^a1 * p2^a2*···*pn^an;(其中一系列an为指数,pn为质数),为了是n最小,所以应该使指数a1,a2,a3,...,an从最小的开始遍历
4.遍历时利用公式t=(a1+1)*(a2+1)*(a3+1)*······*(an+1)计算每一种a1,a2,a3,..an的组合情况对应的t为多少,此种情况下n(下面代码中的single变量)为多少,是不是应该更新答案
5.遍历完成后即为答案
(补充:理论上是需要遍历a1,a2,a3,a4,a5,a6,a7...an的所有组合情况的,但是题目只要求取前面60个就行,所以遍历a1,a2,a3,a4就够了,且把每一个指数遍历到100(下面代码中的ii变量)也够了)

package 蓝桥杯真题.第十一届.国赛._5_序列求和;

public class Main {

	static int testCount=60;//题目要求计算前60个
	static int ii=100;//每个指数遍历的上限
	static long result[]=new long[61];//用了存放前60个的答案
	public static void main(String[] args) {

		for (int a4 = 0; a4 <= ii; a4++) {
			for (int a3 = 0; a3 <= ii; a3++) {
				for (int a2 = 0; a2 <= ii; a2++) {
					for (int a1 = 0; a1 <= ii; a1++) {
						
						int t=(a1+1)*(a2+1)*(a3+1)*(a4+1);//计算此种指数组合下的t为多少
						if(t<=60) {//稍稍优化一下,大于60的题目不要求计算,优化掉
							long single=(long) (Math.pow(2, a1)*Math.pow(3, a2)*Math.pow(5, a3)*Math.pow(7, a4));//计算此种指数组合下的n为多少
//							System.out.println(a1+" "+a2+" "+a3+" "+a4+"     "+t+" "+single);
							if(single<result[t] || result[t]==0) {//n需要在所有含有t个约数的数中最小,所有计算结果比之前小才更新答案
								result[t]=single;
							}
						}
					}
				}
			}
		}
		
		long sum=0;
		for (int i = 1; i <= testCount; i++) {
			sum+=result[i];
			System.out.print(result[i]+" ");
			if(i%10==0) {
				System.out.println();
			}
		}
		System.out.println("\n"+sum);//最终答案,码字不易,觉得有收获记得点赞评论支持一下
	}
}

//1 2 4 6 16 12 64 24 36 48 
//1024 60 4096 192 144 120 65536 180 262144 240 
//576 3072 4194304 360 1296 12288 900 960 268435456 720 
//1073741824 840 9216 196608 5184 1260 68719476736 786432 36864 1680 
//1099511627776 2880 4398046511104 15360 3600 12582912 70368744177664 2520 46656 6480 
//589824 61440 4503599627370496 6300 82944 6720 2359296 805306368 288230376151711744 5040 
//
//292809912969717649
//1 2 4 6 16 12 64 24 36 48 
//1024 60 4096 192 144 120 65536 180 262144 240 
//576 3072 4194304 360 1296 12288 900 960 268435456 720 
//1073741824 840 9216 196608 5184 1260 68719476736 786432 36864 1680 
//1099511627776 2880 4398046511104 15360 3600 12582912 70368744177664 2520 46656 6480 
//589824 61440 4503599627370496 6300 82944 6720 2359296 805306368 288230376151711744 5040 
//
//292809912969717649

标签:a1,遍历,JavaB,int,题解,60,蓝桥,a3,a2
来源: https://blog.csdn.net/weixin_54430656/article/details/116431675