您的位置:首页 > 其它

HDU 3555 Bomb(数位DP)

2012-09-14 22:14 609 查看
题目链接

题意:给一个n,问1-n多少个含有49的数字。

算是第一个数位DP吧,感觉数位DP只是通过数字之间的关系,写出状态转移方程的,看了别人的状态的转移,我以为我就可以做出来的,谁知,最后计算貌似比状态转移还难理解,至今不太明白为何要先+1,再计算,猜测可能是计算的时候只能计算1 - x-1的合法数字。

我所理解的计算的过程:如67995,先算出60000以内的再计算到67000之间的再计算67900再到67990,最后67995.

PS:为什么要+1呢,以下是我的猜测,试一下数据可以发现如果这个数里面没有存在‘49’,或者最后两位不是48,那么+1根本没有影响,这两种情况会导致最后的结果也会+1,因为前面计算的时候少算1,如4945,4*dp[3][2]+9*dp[2][2]+dp[2][1]....其实这样算会少一种情况,就是4900,最后要+1补回来。如果开始不+1,把代码的中的第43行的if中加上 sum++,计算上这个漏的情况,也可以AC。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define ll __int64
ll dp[101][3];
int p[101];
int main()
{
int i,t,len,z;
ll sum,n;
scanf("%d",&t);
dp[0][0] = 1;
for(i = 1; i <= 19; i ++)
{
dp[i][0] = dp[i-1][0]*10 - dp[i-1][1];
dp[i][1] = dp[i-1][0];
dp[i][2] = dp[i-1][1]+dp[i-1][2]*10;
}
while(t--)
{
memset(p,0,sizeof(p));
scanf("%I64d",&n);
n++;
sum = 0;
len = 1;
while(n >= 10)
{
p[len ++] = n%10;
n = n/10;
}
p[len] = n;
z = 0;
for( i = len; i>=1; i--)
{
sum += dp[i-1][2] * p[i];
if(z)
sum += dp[i-1][0] * p[i];
if(!z && p[i] >4)
sum += dp[i-1][1];
if(p[i+1] == 4 && p[i] == 9)
z = 1;
}
printf("%I64d\n",sum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: