Project_Euler-12 题解

Project_Euler-12 题解

标题

题目

1
2

思路

我们可以从小到大枚举每一个三角形数,然后计算他们的约数个数,从而得到结果。

代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>
//#include "./DBG_text.h"

#define MAX_N 100

typedef long long ll;

ll get_factory(ll n) {
    ll cnt = 0;
    for (ll i = 1, I = sqrt(n); i <= I; i++) {
        if (n % i) continue;
        cnt += 1;
        cnt += (i != n / i);
    }
    return cnt;
}

ll triangle(ll n) {
    return n * (n + 1) >> 1;
}

ll main() {
    ll n = 0;
    while (1) {
        n++;
        // 求第n个三角形数
        ll val = triangle(n);
        // 计算因子个数
        ll cnt = get_factory(val);
        //DBG("cnt = %lld\n", cnt);
        if (cnt <= 500) continue;
        printf("val = %lld, cnt = %lld\n", val, cnt);
        break;
    }
    return 0;
}

优化思路

这里不得不提到 一个定理了:


约数个数定理

约数个数定理:如果一个大于1的正整数 n 可以分解为质因数的形式:n = p1^a1 * p2^a2 * ... * pk^ak,其中 p1, p2, ..., pkn 的不同质因数,a1, a2, ..., ak 是对应的幂次,那么 n 的约数个数就是 (a1+1) * (a2+1) * ... * (ak+1)

举个例子,假设 n = 2^3 * 3^2 * 5^1,那么 n 的约数个数就是 (3+1) * (2+1) * (1+1) = 24


有了这个定理可以得到什么呢?当一个数字n被确定时,我们通过素数快速计算出它的约数个数。

但是前提,我们需要先知道它的素因子是什么,这就需要我们使用线性筛来求解。

不管先不着急,因为我们要求的是三角形数字的因数个数,而不是n的,因此我们需要进一步处理:

具体是这样的做的:

我们设 F ( n ) F(n) F(n) 表示数字 n n n 的因数个数, f ( n ) f(n) f(n) 表示第 n n n 个三角形数字,那么我们可以得到下面的关系:

F ( f ( n ) ) = F ( n ∗ ( n + 1 ) 2 ) F(f(n)) = F(\frac {n * (n + 1)} {2}) F(f(n))=F(2n(n+1))

此时我们发现 n n n n + 1 n + 1 n+1 一定是一奇一偶的关系,并且他们一定互素。


两个互素的数相乘得到的数的因数 ( F ( n ∗ ( n + 1 ) ) F(n * (n + 1)) F(n(n+1))) 的个数等于什么?

F ( n ∗ ( n + 1 ) ) = F ( n ) ∗ F ( n + 1 ) F(n*(n + 1)) = F(n) * F(n + 1) F(n(n+1))=F(n)F(n+1)

为什么呢?因为两个数的最大公因数为1,所以他们没有相同的因数,因此他们两个相乘得到的因数的个数就是他们自己拆解后的因数不断排列组合得到的因数的个数。

举个例子: 5 5 5 6 6 6 5 5 5 的因数个数为 2 2 2 6 6 6 的因数个数为 4 4 4 ,那么他们的乘积就是 30 30 30 30 30 30 的因数个数就是 2 ∗ 4 = 8 2 * 4 = 8 24=8 个。


那么回到上面的式子:

F ( f ( n ) ) = F ( n ∗ ( n + 1 ) 2 ) F(f(n)) = F(\frac {n * (n + 1)} {2}) F(f(n))=F(2n(n+1))

就可以化简为:

F ( f ( n ) ) = F ( n ) ∗ F ( n + 1 ) 2 F(f(n)) = \frac{F(n) * F(n + 1)}{2} F(f(n))=2F(n)F(n+1)

对n分奇偶情况讨论,可以将2化简掉:

当 n 为偶数时: F ( f ( n ) ) = F ( n 2 ) ∗ F ( n + 1 ) 当 n 为奇数时: F ( f ( n ) ) = F ( n ) ∗ F ( n + 1 2 ) 当n为偶数时: F(f(n)) = F(\frac {n}{2}) * F(n + 1) \\ 当n为奇数时: F(f(n)) = F(n) * F(\frac {n + 1} {2}) n为偶数时:F(f(n))=F(2n)F(n+1)n为奇数时:F(f(n))=F(n)F(2n+1)

得到这个公式,我们就可以通过 n n n 来表达第 n n n 个三角形数的因数个数了。

程序的主框架就完成了:

int main() {
    // ... init();
    ll n = 0; 
    while (1) {
        n++;
        ll val;
        val = (n & 1) ? f[n] * f[(n + 1) >> 1] : f[n >> 1] * f[n + 1];
        if (val <= 500) continue;
        printf("n = %lld\n", n * (n + 1) >> 1);
        break;
    }
    return 0;
}

接下来就是怎么确定 F ( n ) F(n) F(n) ,我们必须保证,当我们拿出一个 n n n 的时候,要得到 n n n 对应的因数的个数。

我们可以将 n n n 对应的因数个数存放在数组里。

我们需要找到 n n n 的最小素因子(prime[j]),这个可以通过遍历素数表来实现,但是对于 n n n 本身,我们需要在线性筛中实现( n = i ∗ p r i m e [ j ] n = i * prime[j] n=iprime[j]), i i i 是线性筛的遍历值,在筛中有以下几种情况讨论:

  • n n n为素数时:其因数个数只有1和它本身,因此就是2
  • i i i与某个素数 j j j互素的时候,f[prime[j] * i] = f[prime[j]] * f[i];
  • i i i与某个素数 j j j非互素的时候 f[prime[j] * i] = (f[i] / (cnt[i] + 1)) * (cnt[i] + 2);

优化代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include "./DBG_text.h"
#define MAX_N 100000

typedef long long ll;

int prime[MAX_N + 5];
int f[MAX_N + 5];
int cnt[MAX_N + 5]; // 表示的是数字i中最小素因子的幂次
void init() {
    for (int i = 2; i <= MAX_N; i++) {
        if (!prime[i]) {
            prime[++prime[0]] = i;
            f[i] = 2;
            cnt[i] = 1;
        }
        for (int j = 1; j <= prime[0]; j++) {
            if (i * prime[j] > MAX_N) break;
            prime[i * prime[j]] = 1;
            // == 0 说明不互素并且prime[j]是i最小的素因数,否则说明互素
            if (i % prime[j] == 0) {
            	// 这里的prime[j]就是n的最小素因数,cnt[i]中记录的就是它的幂数
            	// prime[j] * i说明n这个数相对于i这个数的最小素因数增加了1幂,此时需要先让f[i]先除掉原来的最小幂
            	// 然后再乘以新的幂数也就是+2
            	// 这个2中有一个1表示prime[j] * i之后,增加的1幂
            	// 另一个1表示根据约数个数定理而必须+1
                f[prime[j] * i] = (f[i] / (cnt[i] + 1)) * (cnt[i] + 2); // 这句话较难理解
                cnt[prime[j] * i] = cnt[i] + 1;
                break;
            } else {
                f[prime[j] * i] = f[prime[j]] * f[i];
                cnt[prime[j] * i] = 1;
            }
        }
    }
    return ;
}

int main() {
    init();
    ll n = 0; 
    while (1) {
        n++;
        ll val;
        val = (n & 1) ? f[n] * f[(n + 1) >> 1] : f[n >> 1] * f[n + 1];
        if (val <= 500) continue;
        printf("n = %lld\n", n * (n + 1) >> 1);
        break;
    }
    return 0;
}

补充

对于这段代码:
f[prime[j] * i] = (f[i] / (cnt[i] + 1)) * (cnt[i] + 2);

首先要清楚, p r i m e [ i ] prime[i] prime[i] 一定是 i i i 的最小素因数

之后可以用下面的例子来进行理解:

假设 i = p a i = p^a i=pa,那么 f [ i ] = a + 1 f[i] = a + 1 f[i]=a+1 c n t [ i ] = a cnt[i] = a cnt[i]=a。当 p r i m e [ j ] = p prime[j] = p prime[j]=p 时, p r i m e [ j ] ∗ i = p ( a + 1 ) prime[j] * i = p^{(a+1)} prime[j]i=p(a+1),其约数个数 f [ p r i m e [ j ] ∗ i ] f[prime[j] * i] f[prime[j]i] 应该是 a + 2 a + 2 a+2。这正好等于 f [ i ] / ( c n t [ i ] + 1 ) ∗ ( c n t [ i ] + 2 ) f[i] / (cnt[i] + 1) * (cnt[i] + 2) f[i]/(cnt[i]+1)(cnt[i]+2)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/427303.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

alibabacloud学习笔记07(小滴课堂)

讲解Sentinel自定义异常降级-新旧版本差异 讲解新版Sentinel自定义异常数据开发实战 如果我们都使用原生的报错&#xff0c;我们就无法得到具体的报错信息。 所以我们要自定义异常返回的数据提示&#xff1a; 实现BlockExceptionHandler并且重写handle方法&#xff1a; 使用F…

推荐我最近刚发现的5款实用软件

​ 我喜欢发现和分享一些好用的软件&#xff0c;我觉得它们可以让我们的工作和生活更加轻松和快乐。今天给大家介绍五款我最近发现的软件。 1.桌面工具——PowerToys ​ PowerToys是一款由微软开发的免费开源软件&#xff0c;旨在为Windows 10用户提供更多的自定义和增强功能…

无线鼠标键盘怎么连接电脑?这4个连接方法别错过!

“我新买了一个无线鼠标和键盘&#xff0c;想问问应该怎么将它们与电脑进行连接呢&#xff1f;请大家给我分享几个好用的方法吧&#xff01;” 无线鼠标和键盘已经成为现代办公和娱乐的必备工具&#xff0c;它们通过无线技术与电脑连接&#xff0c;省去了线缆束缚&#xff0c;让…

dvwa靶场xss通关

原理 XSS漏洞是攻击者将恶意代码注入到合法网页中&#xff0c;当用户浏览该页面时&#xff0c;恶意代码会被执行&#xff0c;从而获取用户敏感信息或进行其他攻击。 形成原因 网站对用户输入数据的过滤不严格或不完备&#xff0c;攻击者可以根据这个漏洞向网站提交恶意代码&am…

常用git 打tag命令

1.查看所有tag git tag 2.创建 v5.0.0的tag git tag v5.0.0 git tag &#xff08;创建后查看&#xff09; 3.推送到远程tag git push origin v5.0.0 4.删除远程tag git push origin --delete v5.0.0 5.删除本地tag git tag -d v5.0.0 6.添加带有备注信息的tag git tag v5.…

【Redis】Redis 实现分布式Session

Cookie 保存在客户端浏览器中&#xff0c;而 Session 保存在服务器上。客户端浏览器访问服务器的时候&#xff0c;服务器把客户端信息以某种形式记录在服务器上&#xff0c;这就是 Session。客户端浏览器再次访问时只需要从该 Session 中查找该客户的状态就可以了。 在实际工作…

护眼灯有效果吗怎么样?推荐五款值得入手的护眼台灯

随着护眼台灯被越来越多的人解锁新的护眼攻略&#xff0c;它的产品热度也越来越高&#xff0c;而且光线柔和&#xff0c;是一款非常不错的照明用具。但是也有不少用户反馈买到的护眼台灯效果不好&#xff0c;有时候还会觉得刺眼&#xff0c;有些不合格的台灯使用时间一久还会散…

Vue3_2024_3天【Vue3组合式API~响应式及toRefs】

第一&#xff1a;vue3 中可以两个script标签 第一个&#xff1a;声明组件名 第二个&#xff1a;setup语法糖&#xff08;默认 lang语言是js语言&#xff0c;修改语言须保持一致&#xff09; 若想去掉一个script标签&#xff08;声明组件名称&#xff09;&#xff0c;则可使用插…

前端- 基础 表单标签 - 使用场景及组成

大家都有到银行去办理业务的时候&#xff0c;大多数情况下会填一些 纸质的表之类的东西如下图 而我们在网页中也会经常遇到 像现实生活中在银行填表那样的情景&#xff0c;如下图 &#xff1a; 上示就是 网页中的表单的使用场景了 表单标签 &#xff1a; 为什么需要表单 …

GIS开发应用于哪些领域?就业方向有哪些?分别需要什么技能?

本文适用于GIS专业相关的大二、大三、大四的同学以及部分在职GIS工作者。在这里你将看到&#xff1a; 1、GIS领域可以从事的岗位有哪些&#xff0c;分别需要什么技能&#xff1f; 2、如何选择最合适自己的发展方向&#xff1f; 一、地理信息行业岗位简述 ▶ 上游数据部分 …

Python CGI编程

文章目录 什么是CGICGI架构Web服务器支持及配置CGI程序示例CGI环境变量GET和POST方法GET方法POST方法区别注意事项 使用POST方法传递数据1. 创建HTML表单2. 编写CGI脚本3. 配置服务器4. 提交表单5. 服务器处理请求注意事项 通过CGI程序传递checkbox数据创建HTML表单编写CGI脚本…

EMO: Emote Portrait Alive - 阿里HumanAIGC

EMO: Emote Portrait Alive - 阿里HumanAIGC 最近这一个星期&#xff0c;也就是2月28日的时候&#xff0c;阿里巴巴的HumanAIGC团队发布了一款全新的生成式AI模型EMO&#xff08;Emote Portrait Alive&#xff09;。EMO仅需一张人物肖像照片和音频&#xff0c;就可以让照片中的…

抖音视频评论采集工具|短视频批量下载软件

《抖音视频评论采集工具——解放双手的智能助手》 在数字化时代&#xff0c;抖音视频已成为人们获取信息、娱乐放松的重要来源之一。针对抖音视频评论的采集需求&#xff0c;我们推出了一款功能强大的软件&#xff0c;让您轻松实现评论批量提取&#xff0c;QQ:290615413提高工作…

mirthConnect忽略HTTPS SSL验证

mirthConnect SSL忽略验证 1、下载https网站证书 点击不安全---->证书无效 2、查看mirth 秘钥库口令 在mirthConnect 的conf目录下面keystore.storepass 3、导入证书到本地 在jdk的bin目录下面执行 keytool -importcert -file "下载的网站证书路径" -keysto…

win11修改网络算法为BBR2_提升网络环境质量

Win11 BBR2 是Google开发的一种高效的网络拥塞控制算法&#xff0c;玩 Linux 的朋友应该对它还有锐速不陌生。相比Windows默认使用的 CUBIC 算法&#xff0c;BBR2 在网络吞吐量、延迟、全局性能等方面都有一定优势。 如果你日常网络经常丢包或者高延迟可以尝试切换为BBR2算法。…

基于SpringBoot的在线拍卖系统(附项目源码+论文)

摘要 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单管理、留言板管理、系统管理&#xff0c;用户&#xff1b;首页、个人中心、历史竞拍管理、竞拍订单管理、留言板管理&#xff0…

Nucleic Acids Research | scATAC-seq+CUTTag探究关键转录因子对视网膜细胞分化的调控作用

在中枢神经系统发育过程中&#xff0c;多能神经祖细胞如何产生不同的神经细胞类型仍然知之甚少。最近的scRNA-seq研究已经描绘了包括神经视网膜在内的许多神经系统中单个神经细胞类型的发育轨迹。进一步了解神经细胞多样性的形成需要了解表观遗传景观如何沿着个体细胞谱系变化以…

智慧草莓基地:Java与SpringBoot的技术革新

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

EthSign联合创始人 POTTER LI 确认出席Hack .Summit() 香港区块链开发者大会!

thSign联合创始人 POTTER LI确认将出席由 Hack VC 主办&#xff0c;并由 AltLayer 和 Berachain 联合主办&#xff0c;与 SNZ 和数码港合作&#xff0c;由 Techub News 承办的Hack.Summit() 2024区块链开发者盛会。 Potter Li&#xff0c;南加州大学应有数学系&#xff0c;南加…

数字化转型导师坚鹏:金融机构数字化转型情况、政策及法规解读

金融机构数字化转型总体情况、政策及法规解读 课程背景&#xff1a; 很多学员存在以下问题&#xff1a; 不知道金融机构数字化转型总体情况&#xff1f; 不清楚金融机构数字化转型相关政策&#xff1f; 不知道金融机构数字化转型相关法规&#xff1f; 课程特色&#xf…