有趣的数 算法的题解(数位DP问题)

来源:互联网 发布:stm32f103tbu6编程 编辑:程序博客网 时间:2024/06/06 09:02

有趣的数 算法的题解(数位DP问题)

1. 想了解数位DP问题的可以先参考该文档

2. 问题概述

问题描述
我们把一个数称为有趣的,当且仅当:

  1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
  2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。
  3. 最高位数字不为0。

因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。
请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。

输入格式

输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。

输出格式

输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。

样例输入

4

样例输出

3

3. 问题求解

首先定义f[i]表示为i位数满足条件的组合数。
f[i,2]表示头为2的后面i位共有满足条件的组合数。
根据图可以看出20(是指第一位为2第二位为0,当然倒过来也是成立的)后面可能的组合和200后面可以选择的组合是相同的,这点必须要先明白。这样就有如下等式成立:

f[i, 200] = f[i, 20]f[i, 220] = f[i, 20]

图

下面开始进行迭代公式:

因为第一个数字必须为2否则会违反规则,所以有如下公式:f[i] = f[i-1, 2]/意思为i位数的满足规则的组合数与2为头剩下的i-1位满足规则的组合数相等。另外,f[i]即为我们所求的在i位数下的组合数。第一位为2,第2位上只能是0、2、3之中的一个,所以可以有如下公式:f[i-1, 2] = f[i-2, 20] + f[i-2, 22] + f[i-2, 23]根据前面公式,有f[i-2, 22] = f[i-2, 2]同理有如下公式:f[i-2, 20] = f[i-3, 200] + f[i-3, 201] + f[i-3, 202] + f[i-3, 203] = f[i-3, 20] + f[i-3, 201] + f[i-3, 20] + f[i-3, 203]f[i-2, 22](=f[i-2, 2]) = f[i-3, 220] + f[i-3, 222] + f[i-3, 223] = f[i-3, 20] + f[i-3, 2] + f[i-3, 23]f[i-2, 23] = f[i-3, 230] + f[i-3, 233] = f[i-3, 230] + f[i-3, 23]f[i-3, 230] = f[i-4, 2300] + f[i-4, 2301] + f[i-4, 2303] = f[i-4, 230] + f[i-4, 2301] + f[i-4, 230]f[i-3, 201] = f[i-4, 2011] + f[i-4, 2012] + f[i-4, 2013] = f[i-4, 201] + f[i-4, 201] + f[i-4, 2013]公式里面的{2}、{20}、{23}、{201}、{203}、{2031}称为数码。

另外因为2013后面的数字只能为1或者3,组合数为2,即

f[1, 2013] = 2;可以推导出f[i, 2013] = 2^(i);

下面就是数列的计算,高中已经学过了,计算的结果为

f[i] = f[i-1, 2] = (i-1)(i-4)2^(i-3)+i-1

从而得到的结果为N依次为4到15,结果为

Columns 1 through 7       3          20          85         294         903        2568        6921Columns 8 through 12   17930       45067      110604      266253      630798

用笔算大概就是这个思路。
通过程序实现,就是针对上面的迭代公式进行迭代。
java程序代码如下:

package test;import java.util.Arrays;public class test {    public static void main(String[] args) {        // TODO Auto-generated method stub        int N = 15;        long[] count = new long[8];        count[6] = 0;        count[7] = 1;        long mod = 1000000007;        for (int i = 2; i <= N; ++i) {            long[] newCount = new long[8];            newCount[0] = (count[0] * 2 + count[1] + count[3]) % mod;            newCount[1] = (count[1] * 2 + count[2] + count[5]) % mod;            newCount[2] = (count[2] + count[6]) % mod;            newCount[3] = (count[3] * 2 + count[4] + count[5]) % mod;            newCount[4] = (count[4] + count[7]) % mod;            newCount[5] = (count[5] * 2 + count[6] + count[7]) % mod;            newCount[6] = 0;            newCount[7] = 1;            count = newCount;            System.out.println(count[0]);        }    }}
1 0
原创粉丝点击