HDU 5808[数位dp]

Posted 徐暾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 5808[数位dp]相关的知识,希望对你有一定的参考价值。

/*
题意:
给你l和r,范围9e18,求l到r闭区间有多少个数字满足,连续的奇数的个数都为偶数,连续的偶数的个数都为奇数。
例如33433符合要求,44不符合要求。不能含有前导零。


思路:
队友说是数位dp...我都反映不过来。
知道是数位dp以后,思路就显而易见了。
dp的方法是最后一位的性质,是偶数还是奇数,是连续的第偶数个还是第奇数个。所以一共只有四种状态,而题目中最多19位数字...
用了以上的方法,我们可以轻易解决有n为数字的符合要求的数字的个数。
问题是如何考虑边界条件。
所以我们可以先判断l和r有多少位。然后提前打表,中间的位数直接加到答案上来就好。
现在我们讨论跟l和r位数相同的在l到r范围内的,即大于等于l,小于等于r的个数。
假如l和r位数相同,那么我们可以用小于等于r的减去小于等于l的,然后特判l是不是。
位数不同,可以直接求和l位数相同的,大于等于l的加上和r位数相同的小于等于r的。
所以现在问题转化为,位数确定的情况下,小于等于或者大于等于某个数的符合条件数的个数有多少。
类似dfs,依次讨论前几位大于等于某位或者小于等于某位有多少个...(这个大概是数位dp的核心?)
【简单说一下,第i次统计的数目是,假如第i位大于边界值,而前i-1位等于边界值的符合要求的数字的数目,这样一直统计到i+1...】
*/













#include<bits/stdc++.h>
using namespace std;
bool panduan(unsigned long long num)
{
    int curr=0;
    int len=0;
    while(num)
    {
        int temp=num%10;
        if(curr==0)
        {
            if(temp%2)
                curr=1;
            else curr=2;
            len=1;
        }
        else
        {
            if(curr==1)
            {
                if(temp%2)
                    len++;
                else
                {
                    if(len%2)
                        return false;
                    len=1;
                    curr=2;
                }
            }
            else
            {
                if(temp%2==0)
                    len++;
                else
                {
                    if(len%2==0)
                        return false;
                    len=1;
                    curr=1;
                }
            }
        }
        num/=10;
    }
    if((curr==1)&&(len%2==0))
        return true;
    if((curr==2)&&(len%2==1))
        return true;
    return false;
}
int get_wei(unsigned long long t){
    int rel=0;
    while(t>0){
        rel++;
        t/=10;
    }
    return rel;
}
unsigned long long dp[20][4];
unsigned long long biao[30];
void dabiao(){
    for(int i=1;i<=19;i++){
        memset(dp,0,sizeof(dp));
        for(int j=1;j<=i;j++){
            if(j==1){
                dp[j][0]+=4;
                dp[j][2]+=5;
            }
            dp[j][0]+=(dp[j-1][1]+dp[j-1][3])*5;
            dp[j][1]+=dp[j-1][0]*5;
            dp[j][2]+=(dp[j-1][0]+dp[j-1][3])*5;
            dp[j][3]+=dp[j-1][2]*5;
        }
        biao[i]=dp[i][0]+dp[i][3];
    }
}
int fenjie[30];
unsigned long long dayudengyu(unsigned long long l){
    unsigned long long rel=0;
    unsigned long long ll=l;
    int num=0;
    while(ll>0){
        fenjie[num++]=ll%10;
        ll/=10;
    }
    for(int i=0;i<num/2;i++){
        swap(fenjie[i],fenjie[num-i-1]);
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<num;i++){
        for(int j=i;j<num;j++){
            if(j==i){
                if(fenjie[i]&1){
                    if(j==0){
                        dp[j][0]=dp[j][2]=(10-fenjie[i])/2;
                    }
                    else{
                        int ttt=(10-fenjie[i])/2;
                        dp[j][0]=(dp[j-1][1]+dp[j-1][3])*ttt;
                        dp[j][1]=dp[j-1][0]*ttt;
                        dp[j][2]=(dp[j-1][0]+dp[j-1][3])*ttt;
                        dp[j][3]=dp[j-1][2]*ttt;
                    }
                }
                else{
                    if(j==0){
                        dp[j][0]=(10-fenjie[i])/2-1;
                        dp[j][2]=(10-fenjie[i])/2;
                    }
                    else{
                        int ttt=(10-fenjie[i])/2;
                        dp[j][0]=(dp[j-1][1]+dp[j-1][3])*(ttt-1);
                        dp[j][1]=dp[j-1][0]*(ttt-1);
                        dp[j][2]=(dp[j-1][0]+dp[j-1][3])*ttt;
                        dp[j][3]=dp[j-1][2]*ttt;
                    }
                }
            }
            else{
                dp[j][0]=(dp[j-1][1]+dp[j-1][3])*5;
                dp[j][1]=dp[j-1][0]*5;
                dp[j][2]=(dp[j-1][0]+dp[j-1][3])*5;
                dp[j][3]=dp[j-1][2]*5;
            }
        }
        rel+=dp[num-1][0]+dp[num-1][3];
        memset(dp,0,sizeof(dp));
        for(int j=0;j<=i;j++){
            if(j==0){
                if(fenjie[j]&1)dp[j][2]=1;
                else dp[j][0]=1;
            }
            else{
                if(fenjie[j]&1){
                    dp[j][2]=(dp[j-1][0]+dp[j-1][3]);
                    dp[j][3]=dp[j-1][2];
                }
                else{
                    dp[j][0]=(dp[j-1][1]+dp[j-1][3]);
                    dp[j][1]=dp[j-1][0];
                }
            }
        }
    }
    return rel+dp[num-1][0]+dp[num-1][3];
}
unsigned long long xiaoyudengyu(unsigned long long l){
    unsigned long long rel=0;
    unsigned long long ll=l;
    int num=0;
    while(ll>0){
        fenjie[num++]=ll%10;
        ll/=10;
    }
    for(int i=0;i<num/2;i++){
        swap(fenjie[i],fenjie[num-i-1]);
    }
    memset(dp,0,sizeof(dp));
    for(int i=0;i<num;i++){
        for(int j=i;j<num;j++){
            if(j==i){
                if(fenjie[i]&1){
                    if(j==0){
                        dp[j][0]=fenjie[i]/2;
                        dp[j][2]=fenjie[i]/2;
                    }
                    else{
                        unsigned long long ttt=(fenjie[i])/2+1;
                        unsigned long long tt=fenjie[i]/2;
                        dp[j][0]=(dp[j-1][1]+dp[j-1][3])*ttt;
                        dp[j][1]=dp[j-1][0]*ttt;
                        dp[j][2]=(dp[j-1][0]+dp[j-1][3])*tt;
                        dp[j][3]=dp[j-1][2]*tt;
                    }
                }
                else{
                    if(j==0){
                        dp[j][0]=max(fenjie[i]/2-1,0);
                        dp[j][2]=(fenjie[i])/2;
                    }
                    else{
                        int ttt=max(0,fenjie[i]/2);
                        int tt=fenjie[i]/2;
                        dp[j][0]=(dp[j-1][1]+dp[j-1][3])*(ttt);
                        dp[j][1]=dp[j-1][0]*(ttt);
                        dp[j][2]=(dp[j-1][0]+dp[j-1][3])*(tt);
                        dp[j][3]=dp[j-1][2]*tt;
                    }
                }
            }
            else{
                dp[j][0]=(dp[j-1][1]+dp[j-1][3])*5;
                dp[j][1]=dp[j-1][0]*5;
                dp[j][2]=(dp[j-1][0]+dp[j-1][3])*5;
                dp[j][3]=dp[j-1][2]*5;
            }
        }
        rel+=dp[num-1][0]+dp[num-1][3];
        //cout << rel << endl;
        memset(dp,0,sizeof(dp));
        for(int j=0;j<=i;j++){
            if(j==0){
                if(fenjie[j]&1)dp[j][2]=1;
                else dp[j][0]=1;
            }
            else{
                if(fenjie[j]&1){
                    dp[j][2]=(dp[j-1][0]+dp[j-1][3]);
                    dp[j][3]=dp[j-1][2];
                }
                else{
                    dp[j][0]=(dp[j-1][1]+dp[j-1][3]);
                    dp[j][1]=dp[j-1][0];
                }
            }
        }
    }
    return rel+dp[num-1][0]+dp[num-1][3];
}
int main(){
    int a;
    dabiao();
    int cas=0;
    scanf("%d",&a);

    while(a--){
        cas++;
        unsigned long long l,r,ll,rr;
        unsigned long long rel=0;
        scanf("%llu%llu",&l,&r);
        int st=get_wei(l);
        int ed=get_wei(r);
        for(int i=st+1;i<ed;i++){
            rel+=biao[i];
        }
        if(st==ed){
            rel+=xiaoyudengyu(r);
            rel+=panduan(l);
            rel-=xiaoyudengyu(l);
        }
        else{
            rel+=dayudengyu(l);
            rel+=xiaoyudengyu(r);
        }
        printf("Case #%d: ",cas);
        printf("%llu\n",rel);
    }

}

 

以上是关于HDU 5808[数位dp]的主要内容,如果未能解决你的问题,请参考以下文章

HDU 2089 不要62(数位dp)

hdu 2089 不要62 数位DP入门

HDU 3555Bomb 数位DP

hdu3734(数位dp)

HDU 6156 Palindrome Function 数位DP

HDU 3709 Balanced Number (数位DP)