首页 > 其他 > 详细

【数位DP】HDU 2089 不要62

时间:2020-06-04 23:25:50      阅读:58      评论:0      收藏:0      [点我收藏+]

HDU 2089 不要62

int dp[10][2];
//dp[i][0]表示当前到哪一位,且前一位不是6
//dp[i][1]表示当前到哪一位,且前一位是6
int a[20];

LL dfs(int pos,bool six,bool limit){
//pos搜到的位置(从高位到低位),lead判断是否有前导零,limit判断是否有最高位限制
    int ans = 0;
    if (pos == -1) return 1;
    //搜到最底部,此时数字为个位数并且跳过了4,满足题意,算1个
    if (!limit && dp[pos][six] != -1) return dp[pos][six];
    //如果没有最高位限制且要用到的dp数组已经更新过,直接返回这个结果
    int end = limit ? a[pos] : 9;
    //决定第pos位所能遍历的数字范围
    //如果有最高位限制,则第pos位数字范围最多到原数字的第pos位数字(如原数字4521,不能算出5xxx来)
    //(注意:虽然拆分数字的时候将各个数位倒着储存了,但dfs时也是倒着来的,两者方向其实一致,所以取的是a[pos])
    for (int i = 0; i <= end; i++) {
        if (i == 4 || six && i == 2) continue;
        //这一位是4,跳过;或者前一位是6且这一位是2,构成62,跳过
        ans += dfs(pos - 1, i == 6, limit && i == end);
        //搜低位的dp结果,如果当前有最高位限制且这一位的数字已经是最大的了,则下一位也有最高位限制
        //(如原数字4521,当前搜到4xxx,则接下来最多45xx,不能是46xx)
    }
    if (!limit) dp[pos][six] = ans;
    //如果没有最高位限制,更新dp数组
    return ans;
    //更新dp数组并将结果返回上一层
}

LL part(LL x)//把数按位拆分
{
    int len = 0;
    while (x) {
        a[len++] = x % 10;
        //从a[0]开始,并且是倒着的
        //如1234,在数组中为4321
        x /= 10;
    }
    memset(dp, -1, sizeof dp);
    return dfs(len-1,false,true);
    //从len-1开始,即从x的最高位数字开始
}

int main()
{
   ios::sync_with_stdio(false);
   // int t; cin >> t; while (t--)
    LL l, r;
    while(cin>>l>>r)
    {
        if (!l && !r) break;
        cout << part(r) - part(l-1)<<endl;
    }

	return 0;
}

【数位DP】HDU 2089 不要62

原文:https://www.cnblogs.com/streamazure/p/13046963.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!