您的位置:首页 > 其它

hdu 5898 odd-even number (数位dp)

2016-10-06 15:32 465 查看
题意:

一个数中,每位上数连续是奇数的长度是偶数,每位上数连续是偶数的长度是奇数的数称为odd-even number, 问区间l到r之间的odd-even number数有多少个。l,r的范围为1到9e18.

解题思路:

数位dp,dp[pos][status][ismax],pos记录当前位置,ismax记录当前是否是边界值,status记录当前状态, 奇数长度为奇数为1,奇数长度为偶数为2,偶数长度为基数为3, 偶数长度为奇数为4,另外加一个状态0记录前导零。

为什么要记录是否有前导零呢,对于我这种初入数位dp的菜鸟来说这才是这题最大的难点,仔细去想数位dp的搜索方式,每一位都是从0搜索到最大值,那么中间过程中肯定会出现00123,01,02这样的数,前面出现的多余的0势必对奇偶判断产生影响,所以要加一个状态记录前导零。

接下来就是数位dp的一般操作了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int num[20];
long long dp[20][5];
long long dfs(int pos, int status, bool ismax)
{
long long ret=0;
if(pos<0)
{
if(status==2 || status==3)return 1;
else return 0;
}
if(!ismax && dp[pos][status]>0)return dp[pos][status];
int bmax=ismax?num[pos]:9;
int i;
for(i=0; i<=bmax; i++)
{
int xstatus;
if(status)
{if(i%2)
{
if(status==1)xstatus=2;
if(status==2)xstatus=1;
if(status==3)xstatus=1;
if(status==4)continue;  //出先之前是偶数位长度是偶数而当前位是奇数时,之后肯定已不满足条件,所以剪枝
}
else
{
if(status==1)continue;  //出现之前是奇数位长度位奇数而当前位是偶数时,之后肯定已不满足条件,所以剪枝
if(status==2)xstatus=3;
if(status==3)xstatus=4;
if(status==4)xstatus=3;
}
}else
{
if(!i)
{
ret+=dfs(pos-1, 0, 0);
continue;
}
else
{
if(i%2)
{
xstatus=1;
}
else xstatus=3;
}
}
ret+=dfs(pos-1, xstatus, i==bmax && ismax);
}
return ismax?ret: dp[pos][status]=ret;
}
int cai(long long x)
{
int len=0;
while(x>0)
{
num[len++]=x%10;
x/=10;
}
return len;
}
int main()
{
int t;
scanf("%d", &t);
int k=1;
for(k=1; k<=t; k++)
{
long long n, m;
scanf("%lld%lld", &n, &m);
memset(dp,-1,sizeof(dp));
int lenlen=cai(n-1);
long long ansl= dfs(lenlen-1, 0, true);
memset(dp,-1,sizeof(dp));
int len=cai(m);
long long ansr=dfs(len-1, 0, true);
printf("Case #%d: %lld\n", k, ansr-ansl);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: