您的位置:首页 > 其它

HDU 3555 Bomb(数位DP)

2013-09-19 11:37 357 查看
http://acm.hdu.edu.cn/showproblem.php?pid=3555

题意:0-n之间有多少个数包含"13"的

分析:dp[pos][have]

pos代表当前的位置
have0表示前面出现的数字里没有49
have1表示前面结尾的位置是4
have2表示前面出现的数字里有49了

#include<string.h>
#include<stdio.h>
const int MN=100;
#define LL long long
LL dp[MN][10];//dp[i,j]i长度可以任意数的个数
int digit[MN];
LL n;

//have0表示前面的没有49,have1表示已4结尾,have2表示前面包含了49
LL DFS(int pos,int have,int doing)//pos表当前位置
{
if(pos==-1) return have==2;
//表示后面长度可以任意数且已经搜索过
if(!doing && dp[pos][have]!=-1) return dp[pos][have];
int end=doing?digit[pos]:9;
LL ans=0;
for(int i=0; i<=end; i++)
{
int nhave=have;
if(have==0 && i==4)
nhave=1;
if(have==1 && i==9)
nhave=2;
if(have==1 && i!=9)
nhave=0;
if(have==1 && i==4)//前面的数十4,如果当前的是4,这种情况别忘记
nhave=1;
ans+=DFS(pos-1,nhave,doing && i==end);
//前面取到了最大数,后面的数不能任意取了
}
if(!doing)
{//在pos以后为可以取任意数的情况下,这种状态是饱满的,做一个记忆储存,供后面查询使用
dp[pos][have]=ans;
}
return ans;
}

LL cal()
{
int len=0;
while(n)
{
digit[len++]=n%10;
n/=10;
}
return DFS(len-1,0,1);
}

int main()
{
int i,j,T;
scanf("%d",&T);
while(T--)
{
scanf("%I64d",&n);
memset(dp,-1,sizeof(dp));
printf("%I64d\n",cal());
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: