题目描述
链接:牛客网 三角形个数
分析与代码
非常好的一道题目,我一直认为找规律、分类的题是相当重要的,这也能变向提高你的问题分析能力,思维能力,状态划分能力。本题是相当不错的题目,在小学奥数中经常让来计数。大学中就让直接求规律了啊哈哈~
分类
首先,得想到用 增量 的方式来考虑该问题。边场为 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 (n−1)−2(k−1)≥0 简单分类讨论就能得到不论奇数还是偶数的情况项数都能统一到 ( i − 1 ) 2 \frac {(i-1)} 2 2(i−1) 。这就很 妙 了。代码将极大的简化~哈哈哈
#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;
}