[找规律] 三角形个数(牛客+找规律+思维+代码优化)

题目描述

链接:牛客网 三角形个数

小明最近痴迷于斐波那契数列(1,1,2,3,5……),但是最近他又有了新的奇思妙想,就是对于斐波那契数列的相邻的两个数相乘取倒数然后将每一项进行相加,由于小明只喜欢思考不喜欢动手,所以现在他想让你帮他算下这样一个新的数列的前 13 项的和为多少?(结果用分数表示,且保留最简分数)


分析与代码

非常好的一道题目,我一直认为找规律、分类的题是相当重要的,这也能变向提高你的问题分析能力,思维能力,状态划分能力。本题是相当不错的题目,在小学奥数中经常让来计数。大学中就让直接求规律了啊哈哈~

分类

首先,得想到用 增量 的方式来考虑该问题。边场为 n 的三角形就比边长为 n - 1 的三角形多了最底边上构成的三角形,我们只需要统计这些 增量 三角形的个数即可。

将整个图形分为正三角形和倒三角形,来分别考虑其规律,我就在这贴官方的本次比赛的题解了:

这个分类的思想就很重要,就能将问题不重不漏的进行简化!

在这里插入图片描述

但是我觉得官方给的这个 Java 代码不太容易使人理解…下面我自己写了份,加了备注。

第一版代码,计算每一层的三角形增量的个数

#include <iostream>

using namespace std;

typedef long long LL;

const int N = 20210420, MOD = 1e9+7;

LL a[N], b[N], c[N];

int main() {
    int n = 20210411;

    for (LL i = 2; i <= n; i ++ ) {
        if (i & 1) b[i] += (b[i - 2] + (i - 1)) % MOD; // 奇数,b[i] 为第i层,且i为奇数的增量倒三角形
        else c[i] += (c[i - 2] + (i - 1)) % MOD; // 偶数,同理
    }

    for (LL i = 1; i <= n; i ++ ) {
    	// 它的增量是 (i * (i + 1)) / 2,再顺手算一个前缀和
        a[i] += a[i - 1] + (i * (i + 1)) / 2 % MOD; // a[i] 是第1~i层的所有正三角形个数
        if (i & 1) a[i] += b[i];	// 这样写就很好理解了,奇数层加奇数层的倒三角
        else a[i] += c[i];
        a[i] %= MOD;
    }
    cout << a[n] << endl;
    return 0;
}

第二版代码,直接计算前 i 层的正三角形个数、倒三角形的个数:

#include <iostream>

using namespace std;

typedef long long LL;

const LL N = 20210420, MOD = 1e9+7;

LL a[N], b[N], c[N];

int main() {
    int n = 20210411;

    // 每一层的正三角形个数
    for (LL i = 1; i <= n; i ++ ) a[i] += (a[i - 1] + (i * (i + 1) / 2)) % MOD;

    // 每一层新增的倒三角形个数
    for (LL i = 2; i <= n; i ++ ) {
        if (i & 1) b[i] += (b[i - 2] + (i - 1)) % MOD;          // 奇数
        else c[i] += (c[i - 2] + (i - 1)) % MOD;                // 偶数
    }
    
    for (LL i = 1; i <= n; i ++ ) b[i] = (b[i] + b[i - 1]) % MOD, c[i] = (c[i] + c[i - 1]) % MOD;

    cout << (a[n] + b[n] + c[n]) % MOD << endl;
    return 0;
}

第三版代码,在做题过程中,关于倒三角的增量公式确实是 (n-1)+(n-3)+(n-5)+... 其实完全可以用等差数列求和来得到这个增量值。

可以分两种情况:

  • n 为奇数的情况的时候,尾项必然是 0。
  • n 为偶数的情况的时候,尾项必然是 1。
  • 故,只需要计算得到项数即可使用等差数列求和公式 n ( a 1 + a n ) 2 \frac {n(a_1+a_n)} 2 2n(a1+an)
  • 假设项数为 k k k ,此时 d = − 2 d=-2 d=2,即有 ( n − 1 ) − 2 ( k − 1 ) ≥ 0 (n-1)-2(k-1) \geq 0 (n1)2(k1)0 简单分类讨论就能得到不论奇数还是偶数的情况项数都能统一到 ( i − 1 ) 2 \frac {(i-1)} 2 2(i1) 。这就很 了。代码将极大的简化~哈哈哈
#include <iostream>

using namespace std;

typedef long long LL;

const LL N = 20210420, MOD = 1e9+7;

LL a[N], b[N];

int main() {
    LL n = 20210411;

    // 前i层的正三角形个数
    for (LL i = 1; i <= n; i ++ ) a[i] += (a[i - 1] + (i * (i + 1) / 2)) % MOD;

    // 不分奇偶,直接运用等差数列求和公式计算,b[i]为前i层的倒三角个数 
    for (LL i = 1; i <= n; i ++ ) {
        if (i & 1) b[i] = ((i + 1) / 2) * (0 + i - 1) / 2 % MOD;
        else b[i] = ((i + 1) / 2) * (1 + i - 1) / 2 % MOD;
        b[i] =(b[i] + b[i - 1]) % MOD;
    }

    cout << (a[n] + b[n]) % MOD << endl;
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值