hdu 5898 odd-even number (数位dp)

odd-even number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 648    Accepted Submission(s): 357


Problem Description
For a number,if the length of continuous odd digits is even and the length of continuous even digits is odd,we call it odd-even number.Now we want to know the amount of odd-even number between L,R(1<=L<=R<= 9*10^18).
 

Input
First line a t,then t cases.every line contains two integers L and R.
 

Output
Print the output for each case on one line in the format as shown below.
 

Sample Input
 
   
2 1 100 110 220
 

Sample Output
 
   
Case #1: 29 Case #2: 36
 

Source
2016 ACM/ICPC Asia Regional Shenyang Online

题意:求[L,R内“奇偶数”的个数,奇偶数定义:如果一个数中连续的奇数有偶数个,连续的偶数有奇数个,那么这个数就是“奇偶数”
分析:简单数位dp,我们用dp[i][num][cnt],表示第i位为num,如果num为奇数,那么cnt表示和num连续的奇数有cnt个,num为偶数就表示和num连续的偶数有cnt个,显然0<=num<=9,cnt<19;对于i不是最后一位的情况,要考虑中间的cnt满足条件才能向后转移,用记忆化dfs写方便些。
#include
using namespace std;
#define LL long long
int digit[21];
LL dp[21][11][21];
LL dfs(int l,int num,int cnt,bool zero,bool jude)
{
    if(l==0)
    {
        if(num==10) return 0;
        if((num&1)&&!(cnt&1)) return 1;
        if(!(num&1)&&(cnt&1)) return 1;
        return 0;
    }
    if(!jude&&dp[l][num][cnt]!=-1) return dp[l][num][cnt];
    int x=jude?digit[l]:9;
    LL ans=0;
    for(int i=0;i<=x;i++)
    {
        if(zero&&i==0) ans+=dfs(l-1,num,cnt,zero&&i==0,jude&&i==x);//一直是前导零,那么一直填10,不管他
        else
        {
            int a,b;
            if(num==10) a=i,b=1;//表明之前一直是前导零,从这位开始填非零数字
            else
            {
                if(i&1)
                {
                    if(num&1) a=i,b=cnt+1;
                    else
                    {
                        if(!(cnt&1)) continue;
                        a=i;
                        b=1;
                    }
                }
                else
                {
                    if(!(num&1)) a=i,b=cnt+1;
                    else
                    {
                        if(cnt&1) continue;
                        a=i;
                        b=1;
                    }
                }
            }
            ans+=dfs(l-1,a,b,zero&&i==0,jude&&i==x);
        }
    }
    if(!jude) dp[l][num][cnt]=ans;
    return ans;
}
LL get(LL x)
{
    int l=0;
    while(x)
    {
        digit[++l]=x%10;
        x/=10;
    }
    return dfs(l,10,1,true,true);///考虑前导零,如果一直都是前导零,那么我就一直用10填充,到最后跑断一下,10为特殊值
}
int main()
{
    memset(dp,-1,sizeof(dp));
    int T;
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        LL L,R;
        scanf("%lld%lld",&L,&R);
        printf("Case #%d: %lld\n",ca,get(R)-get(L-1));
    }
    return 0;
}


你可能感兴趣的:(DP)