试题编号: | 201312-4 |
试题名称: | 有趣的数 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 我们把一个数称为有趣的,当且仅当: 输入格式 输入只有一行,包括恰好一个正整数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 <bits/stdc++.h>
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;
}