CCF CSP 201312 4.有趣的数

数位dp。(非常规)

这种题光看代码真是头疼,想了一个小时才想明白当时的思路。
思路如下:

题目问你x位有趣的数有多少个,记为c[x],那么就要想出来c[x]怎么用c[x-1]表示。
x位有趣的数一定可以由一个x-1位的数m在末尾添加一个数字而构造出来,分为两种情况:

  1. m是有趣的数
    可以想到,只能在末尾添加13,这两种添加方式都一定有效。
  2. m不是有趣的数
    若在m后添加一个数字能使其变为有趣的数,则m一定是少一个数字(m只违背规则1),且只能少1或者少3。少什么补什么就好了,一定有效。

这样定义了新的两种数A,B

  • A:不是有趣的数,在其末尾添加1就能变为有趣的数。
  • B:不是有趣的数,在其末尾添加3就能变为有趣的数。

对于指定位数的A,B的个数怎么计算?重复使用上述方法,逐渐消减定义复杂度。

#include 
using namespace std;

const int MOD = 1e9 + 7;

long long dp[1001][6];

void cal(int n)
{
	for (int i = 5; i <= n; i++)
	{
		dp[i][0] = dp[i - 1][0];                                    // 只有2
		dp[i][1] = dp[i - 1][1] + dp[i - 1][0];                     // 2,3
		dp[i][2] = 2 * dp[i - 1][2] + dp[i - 1][0];                 // 2,0
		dp[i][3] = 2 * dp[i - 1][3] + dp[i - 1][1] + dp[i - 1][2];  // 2,0,3
		dp[i][4] = 2 * dp[i - 1][4] + dp[i - 1][2];                 // 2,0,1
		dp[i][5] = 2 * dp[i - 1][5] + dp[i - 1][3] + dp[i - 1][4];  // 全部

		dp[i][2] %= MOD;
		dp[i][3] %= MOD;
		dp[i][4] %= MOD;
		dp[i][5] %= MOD;
	}
}

void init()
{
	dp[4][0] = 1;
	dp[4][1] = 3;
	dp[4][2] = 7;  // 失之毫厘 谬以千里
	dp[4][3] = 9;
	dp[4][4] = 5;
	dp[4][5] = 3;
}

int main()
{
	int N;
	cin >> N;
	init();
	cal(N);
	cout << dp[N][5] << endl;
    return 0;
}

你可能感兴趣的:(动态规划,-,数位dp,动态规划,CCF,CSP)