/**
* 数位dp:
* 和hdu 2089 类似,不过这个其实更简单。
* 不过有一点不同的是,在计数的时候,因为要找的是子串“49”,
* 所以不需要考虑在if(num[i] > 9 && last == 4) 的情况
* 而hdu 2089的子串是“62”,也就是当在if(num[i] > 2 && last == 6)情况的时候
* 仍需考虑num[i] > 2,因为这里还有个num[i]取2的数,所以要多加个 dp[i][1];
* 其次就是num[i] == 9的时候,这个一开始想了有点久,为什么num[i]=9, num[i+1]=4
* 的时候不需要算呢? 也就是为什么是if(num[i] > 9 && last == 6) 而不是 if(num[i] >= 9 && last == 6)
* 其实当num[i] = 9, num[i+1] = 4 的时候把flag设成true,也就是表示已经出现了以49xxx形式的数
* 其实这里就已经算了49xxx了,就不用在当前步算49,而是在之后的flag为true的时候都是这种情况。
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <algorithm>
#define DEBUG 0
#define INF 0x1fffffff
#define MAXN 25
typedef long long LL;
using namespace std;
int num[MAXN];
LL dp[MAXN][3]; // 0-所有不存在 1-不存在以9开头 2-存在
LL cal(LL x)
{
int cnt = 1;
while(x)
{
num[cnt++] = x % 10;
x /= 10;
}
int last = 0, flag = 0;
LL ans = 0;
for(int i = cnt - 1; i > 0; i --)
{
ans += dp[i-1][2] * num[i]; // 0 - 4
if(flag)
{
ans += dp[i-1][0] * num[i];
}
else
{
if(num[i] > 4) {
ans += dp[i-1][1];
}
}
if(last == 4 && num[i] == 9)
flag = 1;
last = num[i];
}
return ans;
}
int main()
{
int t;
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i = 1; i < 20; i ++)
{
dp[i][0] = dp[i-1][0] * 10 - dp[i-1][1];
dp[i][1] = dp[i-1][0];
dp[i][2] = 10 * dp[i-1][2] + dp[i-1][1];
}
cin >> t;
while(t --)
{
LL x;
cin >> x;
cout << cal(x+1) << endl;
}
return 0;
}
HDU 3555 数位DP 入门
最新推荐文章于 2019-04-15 09:38:10 发布