题目描述
如图所示,有一个等边三角形①,以每一条边的中点作切割,第一次切割后获得②,即一个下三角形和三个上三角形。后续对每一个三角形都以此法切割,则第二次切割后获得③,以此类推。
输入: 切割次数n
输出: 下三角形的个数,结果对998242353取模
Sample 1
1
1
Sample 2
3
28
思路1
记第n次切割后的上三角形数量为
f
(
n
)
f(n)
f(n),下三角形的数量为
g
(
n
)
g(n)
g(n),则:
n
=
0
→
f
(
n
)
=
1
,
g
(
n
)
=
0
n=0→f(n)=1, g(n)=0
n=0→f(n)=1,g(n)=0
n
=
1
→
f
(
n
)
=
3
,
g
(
n
)
=
1
n=1→f(n)=3, g(n)=1
n=1→f(n)=3,g(n)=1
n
=
2
→
f
(
n
)
=
10
,
g
(
n
)
=
6
n=2→f(n)=10, g(n)=6
n=2→f(n)=10,g(n)=6
n
=
3
→
f
(
n
)
=
36
,
g
(
n
)
=
28
n=3→f(n)=36, g(n)=28
n=3→f(n)=36,g(n)=28
n
=
4
→
f
(
n
)
=
136
,
g
(
n
)
=
120
n=4→f(n)=136, g(n)=120
n=4→f(n)=136,g(n)=120
……
通过对三角形个数寻找规律得,
f
(
n
)
−
g
(
n
)
=
2
n
f(n)-g(n)=2^n
f(n)−g(n)=2n。
此外,
f
(
n
+
1
)
=
3
f
(
n
)
+
g
(
n
)
f(n+1)=3f(n)+g(n)
f(n+1)=3f(n)+g(n),
g
(
n
+
1
)
=
f
(
n
)
+
3
g
(
n
)
g(n+1)=f(n)+3g(n)
g(n+1)=f(n)+3g(n),可以得到如下表达式:
f
(
n
)
=
2
2
n
−
1
+
2
n
−
1
f(n)=2^{2n-1}+2^{n-1}
f(n)=22n−1+2n−1
g
(
n
)
=
2
2
n
−
1
−
2
n
−
1
g(n)=2^{2n-1}-2^{n-1}
g(n)=22n−1−2n−1
这样即可避免在运算过程中使用循环,能节省大笔运算时间;同时也可以采用范围更大的数据类型如unsigned long long存储计算结果,并直接代入n取模求解。
代码1
#include <iostream>
#include <cmath>
#define MAX 998242353
using namespace std;
int f(int n) {
unsigned long long result = pow(2, 2 * n - 1) - pow(2, n - 1);
result %= MAX;
return result;
}
int main() {
int n;
cin >> n;
int result = f(n);
cout << result << endl;
return 0;
}
思路2
以上思路有一个非常致命的缺陷,那就是再大的数据类型也会有上溢的问题,如图所示,在n不小于33时,输出的结果明显有误。
这个时候单纯加long并不是长久之计,需要找到一个在运算过程中取模的方法。根据取模运算的性质可知:
g
(
n
)
m
o
d
D
=
(
2
2
n
−
1
m
o
d
D
−
2
n
−
1
m
o
d
D
)
m
o
d
D
g(n)\ mod\ D=(2^{2n-1}\ mod\ D-2^{n-1}\ mod\ D)\ mod\ D
g(n) mod D=(22n−1 mod D−2n−1 mod D) mod D
此时我们可以分别记
C
=
2
2
n
−
1
m
o
d
D
C=2^{2n-1}\ mod\ D
C=22n−1 mod D,
B
=
2
n
−
1
m
o
d
D
B=2^{n-1}\ mod\ D
B=2n−1 mod D,根据取模运算的性质可知:
2
2
n
−
1
m
o
d
D
=
(
2
2
n
−
2
m
o
d
D
×
2
m
o
d
D
)
m
o
d
D
=
(
2
2
n
−
2
m
o
d
D
×
2
)
m
o
d
D
2^{2n-1}\ mod\ D=(2^{2n-2}\ mod\ D\times 2\ mod\ D)\ mod\ D=(2^{2n-2}\ mod\ D\times 2)\ mod\ D
22n−1 mod D=(22n−2 mod D×2 mod D) mod D=(22n−2 mod D×2) mod D
2
n
−
1
m
o
d
D
=
(
2
n
−
2
m
o
d
D
×
2
m
o
d
D
)
m
o
d
D
=
(
2
n
−
2
m
o
d
D
×
2
)
m
o
d
D
2^{n-1}\ mod\ D=(2^{n-2}\ mod\ D\times 2\ mod\ D)\ mod\ D=(2^{n-2}\ mod\ D\times 2)\ mod\ D
2n−1 mod D=(2n−2 mod D×2 mod D) mod D=(2n−2 mod D×2) mod D
由以上公式,我们可以避免先计算结果后取模,转而采用以上规律去构造循环解决。
代码2
#include <iostream>
#define MAX 998242353
using namespace std;
unsigned int f(int n) {
unsigned int B = 0, C = 0;
unsigned int r = 1;
for (int i = 1; i <= 2 * n - 1; ++i) {
r = (2 * r) % MAX;
if (i == n - 1) {
B = r;
}
if (i == 2 * n - 1) {
C = r;
}
}
return C > B ? (C - B) % MAX : (C + MAX - B) % MAX;
}
int main() {
int n;
cin >> n;
unsigned int result = f(n);
cout << result << endl;
return 0;
}
输出结果:
坑
笔者做这道题的时候一直在研究怎么取模效率更高,忽略了寻找g(n)表达式这一步,因此喜提TLE,望周知。如果以上解法或结果有错误恳请斧正。