我们把一个数称为有趣的,当且仅当:
- 它的数字只包含 0 , 1 , 2 , 3 0,1,2,3 0,1,2,3,且这四个数字都出现过至少一次。
- 所有的 0 0 0 都出现在所有的 1 1 1 之前,而所有的 2 2 2 都出现在所有的 3 3 3 之前。
- 最高位数字不为
0
0
0。
因此,符合我们定义的最小的有趣的数是 2013 2013 2013。
除此以外, 4 4 4 位的有趣的数还有两个: 2031 2031 2031 和 2301 2301 2301。
请计算恰好有 n n n 位的有趣的数的个数。
由于答案可能非常大,只需要输出答案除以 1 0 9 + 7 10^9+7 109+7 的余数。
输入格式
输入只有一行,包括恰好一个正整数
n
n
n。
输出格式
输出只有一行,包括恰好
n
n
n 位的整数中有趣的数的个数除以
1
0
9
+
7
10^9+7
109+7 的余数。
数据范围
4
≤
n
≤
1000
4≤n≤1000
4≤n≤1000
输入样例:
4
输出样例:
3
- 思路:动态规划
假设我们从高位一直到低位对每个位进行赋值,那么我们会发现根据赋值情况,我们可以根据已经使用的数字 ( 0 , 1 , 2 , 3 ) (0,1,2,3) (0,1,2,3)将数据分为 6 6 6种状态:
- 首先我们从最高位开始,由于 0 , 2 0,2 0,2分别需在 1 , 3 1,3 1,3前面而 0 0 0又不能放置在最高位,最高位只能是 2 2 2,因此我们得到第一种状态,即前 n − 1 n-1 n−1位都是为 2 2 2的情况。
- 现在我们再放置一个数,目前有 0 , 1 , 3 0,1,3 0,1,3没用,由于 0 0 0必须在 1 1 1前面,所以我们在放置 1 1 1是必须先放置 0 0 0。此时我们可以放置 0 0 0或者 3 3 3,基于此,我们得到两种状态,一种是前 n − 1 n-1 n−1为只有 2 、 0 2、0 2、0;另一种前 n − 1 n-1 n−1位只有 2 、 3 2、3 2、3。
- 现在我们再放置一个数,对于已经放置
2
2
2和
0
0
0的状态,我们可以放置
1
1
1或
3
3
3,则又得到两种状态,分别是
2
、
0
、
1
2、0、1
2、0、1和
2
、
0
、
3
2、0、3
2、0、3;对于已经放置
2
2
2和
3
3
3的状态,我们只能放置
0
0
0(
0
0
0必须优先放于
1
1
1前面)。得到状态
2
、
3
、
0
2、3、0
2、3、0(此状态和
2
、
0
、
3
2、0、3
2、0、3相同)
4、最后一种所有 0 , 1 , 2 , 3 0,1,2,3 0,1,2,3都被使用
6种状态如下:
0--用了2,剩0,1,3
1--用了0,2,剩1,3
2--用了2,3,剩0,1
3--用了0,1,2,剩3
4--用了0,2,3,剩1
5--0,1,2,3
后面的状态由前面状态转化而来。如:
第
5
5
5种状态全部使用可以由第
5
5
5中状态自身维持或第
3
3
3种状态或第
4
4
4种状态转化而来
转化如下:假设从
n
−
1
n-1
n−1到
n
n
n位
第
5
5
5中状态自身维持:可以在
n
n
n位放置
1
1
1或
3
3
3(维持自身状态不变只能放置
1
1
1或
3
3
3,因为前面已经有
1
,
3
1,3
1,3所以再放
0
,
2
0,2
0,2就会违反规则)
第
3
3
3种状态:可以在
n
n
n位放置
3
3
3
第
4
4
4种状态:可以在
n
n
n位放置
1
1
1
得到如下公式:
s
t
a
t
e
s
[
i
]
[
5
]
=
(
s
t
a
t
e
s
[
j
]
[
3
]
(
达
到
状
态
五
仅
有
在
1
后
加
3
)
+
s
t
a
t
e
s
[
j
]
[
4
]
]
(
达
到
状
态
五
仅
有
2301
)
+
s
t
a
t
e
s
[
j
]
[
5
]
∗
2
(
达
到
状
态
五
仅
有
加
1
/
3
)
states[i][5] = (states[j][3](达到状态五仅有在1后加3) + states[j][4] ](达到状态五仅有2301)+ states[j][5] * 2(达到状态五仅有加1/3) % mod
states[i][5]=(states[j][3](达到状态五仅有在1后加3)+states[j][4]](达到状态五仅有2301)+states[j][5]∗2(达到状态五仅有加1/3);
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1010;
const int mod=1e9+7;
ll n;
ll f[maxn][6];
int main() {
int n;
scanf("%d", &n);
/*6种状态
0--用了2,剩0,1,3
1--用了0,2,剩1,3
2--用了2,3,剩0,1
3--用了0,1,2,剩3
4--用了0,2,3,剩1
5--0,1,2,3
*/
for (int i = 1; i <= n; i++) {
int j = i - 1;
f[i][0] = 1;
f[i][1] = (f[j][0] + f[j][1] * 2) % mod;
f[i][2] = (f[j][0] + f[j][2]) % mod;
f[i][3] = (f[j][1] + f[j][3] * 2) % mod;
f[i][4] = (f[j][1] + f[j][2] + f[j][4] * 2) % mod;
f[i][5] = (f[j][3] + f[j][4] + f[j][5] * 2) % mod;
}
printf("%lld\n", f[n][5]);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int n;
ll dp0=1,dp1,dp2,dp4,dp3,dp5;
int main() {
scanf("%d", &n);
/*
0--用了2,剩0,1,3
1--用了0,2,剩1,3
2--用了2,3,剩0,1
3--用了0,1,2,剩3
4--用了0,2,3,剩1
5--0,1,2,3
*/
for (int i = 1; i <n; i++) {
ll pre0 = dp0, pre1 = dp1, pre2 = dp2, pre3 = dp3, pre4 = dp4, pre5 = dp5;
dp0 = pre0;
dp1 = (pre0 + pre1 * 2) % mod;
dp2 = (pre0 + pre2) % mod;
dp3 = (pre1 + pre3 * 2) % mod;
dp4 = (pre1 + pre2 + pre4 * 2) % mod;
dp5 = (pre3 + pre4 + pre5 * 2) % mod;
}
printf("%lld\n", dp5);
return 0;
}