HDU odd-even number 数位dp

来源:互联网 发布:ucloud云计算 2016 09 编辑:程序博客网 时间:2024/05/17 02:09

题意

在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 10ll 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;}