切割三角形问题——数学归纳法+大数取模

题目描述

如图所示,有一个等边三角形①,以每一条边的中点作切割,第一次切割后获得②,即一个下三角形和三个上三角形。后续对每一个三角形都以此法切割,则第二次切割后获得③,以此类推。
题目描述图
输入: 切割次数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=0f(n)=1,g(n)=0
n = 1 → f ( n ) = 3 , g ( n ) = 1 n=1→f(n)=3, g(n)=1 n=1f(n)=3,g(n)=1
n = 2 → f ( n ) = 10 , g ( n ) = 6 n=2→f(n)=10, g(n)=6 n=2f(n)=10,g(n)=6
n = 3 → f ( n ) = 36 , g ( n ) = 28 n=3→f(n)=36, g(n)=28 n=3f(n)=36,g(n)=28
n = 4 → f ( n ) = 136 , g ( n ) = 120 n=4→f(n)=136, g(n)=120 n=4f(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)=22n1+2n1
g ( n ) = 2 2 n − 1 − 2 n − 1 g(n)=2^{2n-1}-2^{n-1} g(n)=22n12n1
这样即可避免在运算过程中使用循环,能节省大笔运算时间;同时也可以采用范围更大的数据类型如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=(22n1 mod D2n1 mod D) mod D
此时我们可以分别记 C = 2 2 n − 1   m o d   D C=2^{2n-1}\ mod\ D C=22n1 mod D B = 2 n − 1   m o d   D B=2^{n-1}\ mod\ D B=2n1 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 22n1 mod D=(22n2 mod D×2 mod D) mod D=(22n2 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 2n1 mod D=(2n2 mod D×2 mod D) mod D=(2n2 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,望周知。如果以上解法或结果有错误恳请斧正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值