您的位置:首页 > 其它

数位DP——Bomb ( HDU 3555 )

2016-07-18 17:06 281 查看
题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3555

分析:

题意为给除一个数N,求出1-N这些数中含有49的子串的数的个数。初学数位DP,这道题就当例题了。

题解:

首先我们确定状态转移方程

dp[i][j]用于存储符合条件的数的个数

i 代表目前处理的数长度为i

这里dp[i][j]处理的数可以包含前导0

dp[i][0]代表长度为i的数中不含49的数量

dp[i][1]代表长度为i的数中不含49但是最高位为9的数的数量

dp[i][2]代表长度为i的数中包含49的数的数量

代码:

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] = dp[i-2][2]*10+dp[i-1][1];
}


处理:

对于一个数字n,我们假设它的长度为len,并且第i位储存在a[i]中。

首先加上a[i]*剩下i-1位中满足条件的数的个数。

如果高位已经出现过49,加上a[i]*剩下i-1位中不满足条件的数的个数。

如果高位未出现49,且第i位>4,第i-1位为9,则加上剩下i-1位中以9开头的数的个数。

判断高一位和本位是否构成49,更新标志。

代码:

for(int i=len;i>=1;i--)
{
ans+=dp[i-1][2]*a[i];
if(flag)
ans+=dp[i-1][0]*a[i];
if(!flag&&a[i]>4)
ans+=dp[i-1][1];
if(a[i+1]==4&&a[i]==9)
flag=true;
}


注意:

我们在输入n后,需要对n进行+1的操作,因为我们上述操作是统计[1,n)区间内符合条件的数的个数,并没有统计n的情况,n+1是为了不再特殊处理n

我们在获取n的每一位数字时,应该预先多处理一位,令a[len+1]=0,这样做是为了不特殊处理n<10的情况

AC代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define __int64 long long

__int64 dp[25][3];

void Init()
{
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
int i;
for(i = 1;i<=22;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][2]*10+dp[i-1][1];
}
}

__int64 solve(__int64 n)
{
__int64 i,len = 0,a[25],flag = 0,ans = 0;
while(n)
{
a[++len] = n%10;
n/=10;
}
a[len+1] = 0;
for(i = len;i;i--)
{
ans+=dp[i-1][2]*a[i];
if(flag)
ans+=dp[i-1][0]*a[i];
if(!flag && a[i]>4)
ans+=dp[i-1][1];
if(a[i+1] == 4 && a[i] == 9)
flag = 1;
}
return ans;
}

int main()
{
int t;
__int64 n;
scanf("%d",&t);
Init();
while(t--)
{
scanf("%I64d",&n);
printf("%I64d\n",solve(n+1));
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数位DP ACM HDU-3555 算法