ccf-csp 201312-4 有趣的数

 

试题编号: 201312-4
试题名称: 有趣的数
时间限制: 1.0s
内存限制: 256.0MB
问题描述:

问题描述

  我们把一个数称为有趣的,当且仅当:
  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

 

题解:看网上都是直接递推,没有数位dp的,就写个数位dp的吧。

dp[pos][lmit1][limit2][zero][one][three] 表示在pos位,limit1表示前面是否有3,limit2表示前面是否有1,zero,one,three表示是否出现过0,1,3,由于第一位必为2,所以不需要管。

 

#include 
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;

ll dp[1010][2][2][2][2][2];
ll n;

ll dfs(ll pos,ll limit1,ll limit2,ll zero,ll one,ll three)
{
    if(pos == 0)
    {
        if(zero && one && three)
            return 1;
        else
            return 0;
    }

    if(dp[pos][limit1][limit2][zero][one][three] != -1)
        return  dp[pos][limit1][limit2][zero][one][three];

    ll temp = 0;
    for(int i = 0;i <= 3;i++)
    {
        if(limit1 && i == 2)
            continue;
        if(limit2 && i == 0)
            continue;

        temp = (temp + dfs(pos - 1,limit1 || i == 3,limit2 || i == 1,zero || i == 0,one || i == 1,three || i == 3)) % MOD;
    }

    dp[pos][limit1][limit2][zero][one][three] = temp;
    return temp;
}

int main()
{
    scanf("%lld",&n);
    memset(dp,-1,sizeof(dp));
    printf("%lld\n",dfs(n - 1,0,0,0,0,0));
    return 0;
}

 

你可能感兴趣的:(ccf-csp 201312-4 有趣的数)