HDU odd-even number 数位dp

2 篇文章 0 订阅

题意

在l到r区间内求有多少个符合条件“当前数中所有连续的奇数长度是偶数 所有连续的偶数长度是奇数”的个数

分析

典型的数位dp问题
我们设置dp数组时可以根据 dp[pos][pre][len]设定 
表示在pos长度下 前面是pre并且长度是len的个数共有多少

这个方法很巧妙
根据这个结构 我们dfs(pos,pre,len,zero,limit)这样设置递归参数
我们把所有可能符合条件的分支都去搜索一遍
当我们到pos==0的时候 判断一下 此时如果pre和len的奇偶性不同 那么就返回1 表示这个数字
符合条件
因为当我们递归的时候是把所有可能的尝试都去做了一遍 所以如果当下的数 可能产生正确结果
就根据我们设置的dfs结构递归下去 最终都依靠 pos==0的判断 和之前所做的备忘得到结果
和缩小时间复杂度

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int d[20];//1 2 3 4 5 6 7 8 9 10
ll dp[20][20][20];
ll dfs(int pos,int pre,int len,bool zero,bool lim){
    if(pos==0)return (pre&1)!=(len&1);
    if(!lim&&~dp[pos][pre][len])return dp[pos][pre][len];
    ll ans=0;
    int up = lim==0?9:d[pos];
    for(int i=0;i<=up;i++){
        //为了计算得到正确结果 我们尝试把所有可能产生计数的可能都走一遍
        if(zero){//如果存在前导0 那么可能产生计数的情况是 当前位=0或!=0 都要搜索一遍
            if(i==0)ans+=dfs(pos-1,0,0,1,i==up&&lim);//当前位为0 那么继续加一位前导0继续搜索
            else ans+=dfs(pos-1,i,len+1,0,i==up&&lim);//非0 zero=0继续搜索 
        }
        else{
            if(i&1){//如果是奇数
                if(pre&1)ans+=dfs(pos-1,i,len+1,0,i==up&&lim);//继续搜索
                else if(len&1)ans+=dfs(pos-1,i,1,0,i==up&&lim);//如果是偶数 长度是也是奇数 那么改变奇偶性 长度为1 继续搜
            }
            else{
                if(!(pre&1))ans+=dfs(pos-1,i,len+1,0,i==up&&lim);//如果上一位偶数 那么长度递增 继续搜
                else if(!(len&1))ans+=dfs(pos-1,i,1,0,i==up&&lim);//如果上一位是奇数 长度变1继续搜 
            }
        }
    }
    if(!lim)dp[pos][pre][len]=ans;
    return ans;
}
ll solve(ll x){
    int j=0;
    while(x){
        d[++j] = x%10;
        x/=10;
    }
    return dfs(j,0,0,1,1);
}
int main()
{
    int t;
    ll l,r;
    scanf("%d",&t);
    for(int i=1;i<=t;i++){
        scanf("%lld%lld",&l,&r);
        printf("Case #%d: ",i);
        memset(dp,-1,sizeof(dp));
        printf("%lld\n",solve(r)-solve(l-1));
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值