题目描述
用0和1构造一个长度为 的数字串,要求串中不能出现 101 和 111,问能构造出多少个符合条件的串?
比如,当 时,可构出下列满足条件的串:
000
001
010
011
100
110
输入格式
第一行一个正整数 。
输出格式
输出一个整数表示答案,结果可能很大,mod 1000000007后输出(mod的意思是求余,相当于"%")。
样例
样例一输入
5
样例一输出
15
样例二输入
9999
样例二输出
382276560
提示
注意:结果可能会大到超过 long long 的范围,所以题目要求与1000000007取余后再输出结果
思路
划分阶段:
使用 dp 算法,记录前两位数。
状态设计:
表示第i位前一位为0,添加的一位为0;
表示第i位前一位为0,添加的一位为1;
表示第i位前一位为1,添加的一位为0;
表示第i位前一位为1,添加的一位为1。
转移方程:
- 前两位为0,0。;
- 前两位为0,1。;(因为 101 不能出现)
- 前两位为1,0。;
- 前两位为1,1。;(因为 111 不能出现)
边界条件:
当只有1位时,但是记录的是前2位。
我们有一下两种解决方法:
- 直接记录两位的情况,从第3位开始循环,如果输入1位就特判一下;
- 观察到 101 和 111 都以 1 开头,也就是说开头为 0 的没有限制。我们可以把1位当作开头为 0 来 dp,就没有问题了。
第1种方法具有普遍性,第2种方法要看限制的字符串的规律。
代码
#include<bits/stdc++.h>
using namespace std;
int n;
const int mod = 1000000007;
long long a[1000010][2][2] = {0};
int main(){
scanf("%d", &n);
a[1][0][0] = 1;
a[1][0][1] = 1;
for(int i = 2; i <= n; ++ i){
a[i][0][0] = a[i - 1][0][0] + a[i - 1][1][0];
a[i][0][1] = a[i - 1][0][0];
a[i][1][0] = a[i - 1][0][1] + a[i - 1][1][1];
a[i][1][1] = a[i - 1][0][1];
a[i][0][0] %= mod;
a[i][0][1] %= mod;
a[i][1][0] %= mod;
a[i][1][1] %= mod;
}
printf("%lld", (a[n][0][0] + a[n][0][1] + a[n][1][0] + a[n][1][1]) % mod);
return 0;
}