POJ - 3252 Round Numbers

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Leon_liuqinburen/article/details/77483503

题目链接:http://poj.org/problem?id=3252

感谢ECNU_LZJ的博客带来的思路   http://m.blog.csdn.net/ECNU_LZJ/article/details/74330589

数位DP  思路出来了  就直接套模板  不懂模板的可以来这学学http://www.cnblogs.com/zbtrs/p/6106783.html

定义状态dp[pos][one][zero][lead],pos为当前数位, one为前缀中1的个数 , zero为前缀中0的个数, lead,表示当前数位的前缀中有没有1。
注意前导0!假如要计算小于等于12的Round Number个数,12的长度为4,在dfs到3的时候,路径上的数字依次为0011,0的个数大于1的个数,所以3是符合条件的。真的对吗?
实际上前两个0都是前导0,去掉前导0之后,就发现3其实是不合法的了。
所以dfs的时候,维护一个变量lead,表示当前数位的前缀中有没有1。

/**
定义状态dp[pos][one][zero][lead],pos为当前数位, one为前缀中1的个数 , zero为前缀中0的个数, lead,表示当前数位的前缀中有没有1。
注意前导0!假如要计算小于等于12的Round Number个数,12的长度为4,在dfs到3的时候,路径上的数字依次为0011,0的个数大于1的个数,所以3是符合条件的。真的对吗?
实际上前两个0都是前导0,去掉前导0之后,就发现3其实是不合法的了。
所以dfs的时候,维护一个变量lead,表示当前数位的前缀中有没有1。

*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define LL long long
#define MEM(a, b) memset(a, b, sizeof(a))
using namespace std;
LL dp[35][35][35][3];
LL l, r;
int shu[35];
LL dfs(int len, int one, int zero, int lead, bool shangxian)
{
    if(zero + len < one) return 0;  //剪枝
    if (len == 0)
        return zero >= one; //当每位数字都枚举完(即len=0),并且zero >= one的时候才是有效的
    if (!shangxian && dp[len][one][zero][lead] != -1)
        return dp[len][one][zero][lead];  //dp数组的内容应和dfs调用参数的内容相同,除了是否达到上限
    LL cnt = 0;
    int maxx = (shangxian ? shu[len] : 1);
    for (int i = 0; i <= maxx; i++)
    {
        if(i == 0)
        {
            if(lead)  //前缀有1时   当前位的0才有效
                cnt += dfs(len - 1, one, zero + 1, lead, shangxian && i == maxx);
            else
                cnt += dfs(len - 1, one, zero, lead, shangxian && i == maxx);
        }
        else if(i == 1)
            cnt += dfs(len - 1, one + 1, zero, 1, shangxian && i == maxx);
    }
    if (!shangxian)
        dp[len][one][zero][lead] = cnt;
    return cnt;
}

LL solve(LL x)
{
    int k = 0;
    while (x)
    {
        shu[++k] = x % 2;
        x /= 2;
    }
    return dfs(k, 0, 0, 0, 1);
}

int main()
{
    memset(dp, -1, sizeof(dp));
    while(scanf("%I64d %I64d", &l, &r) != EOF)
    {
        printf("%I64d\n", solve(r) - solve(l - 1));
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/Leon_liuqinburen/article/details/77483503
今日推荐