
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3555
题意:
给出一个正整数N,求出1~N中含有数字“49”的数的个数
思路:
采用数位dp的状态转移方程法解
具体如下:
dp[len][state]; dp数组的第一位代表数字的位数,第二位代表状态
状态设定:
dp[i][0] : i 位数字中不含数字49的数的个数
dp[i][1] : i 位数字中不含数字49,但高位是9的数的个数
dp[i][0] : i 位数字中含有数字49的数的个数
状态转移方程:
dp[i][0] = dp[i-1][0] * bit[i] - dp[i-1][1];长度为 i 不含49的数的个数 = 长度为 i-1 中不含49的数的个数*当前数字(因为这个位置可以填0~bit[i]-1),然而,其中包含了bit[i]为4且长度为 i-1 的高位为9,从而组成49····的情况,所以,减去长度为 i-1 的高位为9的数的个数,dp[i-1][1] * 1(这个1代表的是bit[i]为4的情况。
dp[i][1] = dp[i-1][0];长度为 i 的高位为9但不含49的数的个数 = 长度为 i-1 中不含49的数的个数(因为只需在此基础上加上9即可构成 i 位最高位为9的情况)。
dp[i][2] = dp[i-1][2] * bit[i] + dp[i-1][1];长度为 i 的含有数字49的数的个数 = 长度为 i-1 的个数*当前数字,加上长度为 i-1 的高位为9的数字的个数(加个4就成了i位含49的数了)。
代码如下:
#include<iostream>
using namespace std; int n, bit[];
unsigned long long dp[][], num, ans; void init()
{
dp[][] = ;
for (int i = ; i < ; ++i)
{
dp[i][] = dp[i - ][] * - dp[i - ][];
dp[i][] = dp[i - ][];
dp[i][] = dp[i - ][] * + dp[i - ][];
}
} long long solve()
{
int len = , last = ;
bool flag = false;
num++, ans = ;
while (num)
{
bit[++len] = num % ;
num /= ;
}
for (int i = len; i > ; --i)
{
ans += dp[i - ][] * bit[i];
if (flag)ans += dp[i - ][] * bit[i];
if (!flag&&bit[i] > )ans += dp[i - ][];
if (last == && bit[i] == )flag = true;
last = bit[i];
}
return ans;
} int main()
{
cin >> n;
init();
while (n--)
{
cin >> num;
cout << solve() << endl;
}
return ;
}
num++的原因是,该方式求的是开区间,而题目为闭区间,所以要+1
感谢您的阅读,生活愉快~