CCF 201312-4 有趣的数 传送门
这道题似乎就是所谓数位DP, 如果没有接触过这一类题目, 真的是很难会想出完整的方法, 毕竟有6个状态, 然后在状态之间进行递推.
我们定义六种状态, s0-s5, 对每个长度的状态我们都从其他可能推过来的状态推过来.
为什么是六种? 这六种状态是哪六种?
这些状态分为四大类:分别有1,2,3,4个数字的情况.
- 只有一个数字的状态:
-
s0:只有数字2
就这一种了, 为什么? 根据规则我们知道,0必须在1前面,2必须在3前面
所以第一个数字一定是2,这也是所有状态的规则 - 只有两个数字的状态:
-
s1:数字0,2
数字2必须为首数字
s2:数字2,3 - 只有三个数字的状态:
-
s3:数字2,0,1
s4:数字2,0,3 - 四个数字全有的状态:
- s5:数字0,1,2,3
上面定义了所有可能的状态,那么下面就来推导一下状态转移,从而实现递推过程.
对s0状态,无论长度多少,都只能用有一种,所以方程是:
s[0][len] = 1
对s1状态,可由s0末端加入一个0或者上一个s1末端加入0或2,所以方程就是
s[1][len] = s[1][len-1]*2 + s[0][len-1]
对s2状态,可由s0末端加入一个3或者上一个s2末端加入3,所以方程为
s[2][len] = s[2][len-1] + s[0][len-1]
对s3状态,可由s1末端加入一个1或者上一个s3末端加入1或2,所以方程为
s[3][len] = s[3][len-1]*2 + s[1][len-1]
对s4状态,可由s2末端加入一个0或s1末端加上3或者上一个s4末端加入0或3,所以方程为
s[4][len] = s[4][len-1]*2 + s[2][len-1] + s[1][len - 1]
扫描二维码关注公众号,回复:
2777855 查看本文章
对s5状态,可由s3末端加入3或s4末端加入1或者上一个s5末端加入1或3,所以方程为
s[5][len] = s[5][len-1]*2 + s[3][len-1] + s[4][len-1]
按照上述状态转移方程, 转移状态即可.我们的答案就是第六个状态s5
.
100分代码
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
const int mod = 1000000007;
int main()
{
long long s[6][1005] = {}, n;
cin >> n;
for (int len = 1; len <= n; ++len) {
s[0][len] = 1;
s[1][len] = (s[1][len-1]*2 + s[0][len-1])%mod;
s[2][len] = (s[2][len-1] + s[0][len-1])%mod;
s[3][len] = (s[3][len-1]*2 + s[1][len-1])%mod;
s[4][len] = (s[4][len-1]*2 + s[2][len-1] + s[1][len - 1])%mod;
s[5][len] = (s[5][len-1]*2 + s[3][len-1] + s[4][len-1])%mod;
}
cout << s[5][n];
}