再铺地砖
内存限制: 256 Mb时间限制: 1000 ms
题目描述
有一条道路需要铺设地砖,这条道路由 n×2 个方格组成。存在两种规格的地砖,一种是 1×1 规格的,也就是恰好可以覆盖一个方格,另一种是 1×2 规格的。两种规格的砖头的数量没有限制。请计算有多少种方法,将这条道路铺满地砖。
下图是一个例子:
其中花纹是 1×1 规格的,灰色是 1×2 规格的,可以竖放也可以横放。注意,如果上下两行都放置 1×2 规格的砖,它们可以不对齐,例如以下放置方法是允许的:
由于方案数可能很大,输出它模 1,000,000,007 的余数即可。
输入格式
单个正整数:表示 n。
输出格式
单个自然数:表示方案数模 1,000,000,007 的余数。
数据范围
- 对于 30% 的数据,1≤n≤15;
- 对于 70% 的数据,1≤n≤50000;
- 对于 100% 的数据,1≤n≤100000。
样例数据
输入:
3
输出:
22
输入:
4
输出:
71
解析:对于第a[i]的方案数,个以左边对齐的分割点为递推边界,从边界开始向右不能再划分,以此为原则进行递推,有三种情况:
1.边界为i-1:有两种方案,一是单块1x2,二是两块1x1.即a[i-1]*2
2.边界为i-2:有三种情况,一是两块1x2横放,二是一块1x2,两块1x1,1x2放上边,三同二,1x2放下边,即a[i-2]*3;
3.边界为i-3,i-4...1:,对于每个边界,以i-6为例,有两种情况,见下图:
可以得出2*(1+a[1]+a[2]+a[3]....a[i-3])种方案。
结合以上三种情况,得出结果为
a[i]=2*(a[i-1]+a[i-2]+....a[1]+1)+a[i-2],把前边的2*()变成前缀和,即可
详见代码:
#include <bits/stdc++.h>
using namespace std;
long long a[100005];
int main() {
int n;
cin >> n;
a[1] = 2; //初始化
a[2] = 7;
long long sum = 2 * (1 + a[1]); //初始化前缀和
for (int i = 3; i <= n; i++) {
sum += 2 * a[i - 1];//计算前缀和
sum %= 1000000007;
a[i] = a[i - 2] + sum;//递推a[i]
a[i] %= 1000000007;
}
cout << a[n] << endl;
return 0;
}