您的位置:首页 > 其它

HDU 3555 Bomb (数位DP)

2011-08-19 21:05 459 查看
判断(0,n]之间含49的数的个数

具体做法是数位DP , 用3个DP数组分别记录第i位

dp0[i];//不含49的数的个数

dp1[i];//不含49,但第一位是9的个数

dp2[i];//含49个数

则由状态转移方程

dp0[i+1]=dp0[i]*10-dp1[i];

dp1[i+1]=dp0[i];

dp2[i+1]=dp1[i]+dp2[i]*10;

初始为1 0 0 就可以

之后处理个数,按字符串读入之后按位处理,每次递加比该数位小的应有的数,所有如果n本身就是含49的话,就要再+1。

#include <cstdio>
#include <cstring>

typedef long long ll;
const int maxn=25;

ll dp0[maxn];//不含49
ll dp1[maxn];//不含49,但第一位是9的
ll dp2[maxn];//含49

void init ()
{
dp0[0]=1;
dp1[0]=0;
dp2[0]=0;
for (int i=0 ; i<20 ; ++i)
{
dp0[i+1]=dp0[i]*10-dp1[i];
dp1[i+1]=dp0[i];
dp2[i+1]=dp1[i]+dp2[i]*10;// dp2[i]*10表示dp2[i]*9+dp2[i]好理解些
//printf("%lld  %lld  %lld  %lld\n",dp0[i],dp1[i],dp2[i],dp0[i]+dp2[i]);
}
}
int main ()
{
init ();
char str[25];
int num[25];
int cas ;
scanf("%d",&cas);
while (cas--)
{
scanf("%s",str);
int len = strlen (str);
for (int i=0 ; i<len ; ++i)
num[i]=str[i]-48;
ll cnt=num[0]*dp2[len-1];
//printf("%lld\n",cnt);
if(num[0]>4) cnt+=dp1[len-1];
//printf("%lld\n",cnt);
bool flag=0;
for (int i=1 ; i<len ; ++i)
{
cnt+=num[i]*dp2[len-i-1];
//printf("%lld\t",cnt);
if(flag)cnt+=num[i]*dp0[len-i-1];
if(!flag) if(num[i]>4) cnt+=dp1[len-i-1];
//printf("%lld\n",cnt);
if(!flag)if(num[i-1]==4 && num[i]==9)flag=1;
}
for (int i=0 ; i<len-1 ; ++i)
if(num[i]==4 && num[i+1]==9)flag=1;
if(flag)cnt++;
printf("%I64d\n",cnt);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: