zoukankan      html  css  js  c++  java
  • HDU 4734: F(x) (数位DP)

    总结:

    去数字那维的方法,就是改成循环里面枚举当前位(之前的做法是枚举下一位)

    抽象出口,可以从前一个有意义的状态来推导出其意义。

    类型:

    数位DP

    题意:

    F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A 1 * 1.问[0,B]之间满足F(x) <= F(A)的x的数量。 (0 <= A,B < 10 9)

    思路:

    第一次尝试去掉d(数字)那维。

    去掉之后找回来,实际上采用的是枚举当前位的方法。

    去掉那维之后,状态的意思也发生了一定的改变,导致dfs里面的写法也有一定的改变。(num[i-1] ==> num[i])

    定义:dp[i][f] 表示所有i位数中(含前导0),F() <= f  的数的数量。

    那么

    dp[i][f] = sum(dp[i-1][f-j*2i-1])   (j = 0~9(end))

    出口:

    f<0: return 0;

    (无论怎么样也不可能有一个数的F() 是负的)

    i == 0: return 1;

    (理解1:[抽象这个无意义的状态] i==0时,是0位数,0位数并不存在,但 应该 其F() == 0,所以只要是正的f,都满足)

    (理解2:[从前一个有意义的状态考虑] i==0是由i==1这个状态过来的。在i==1时,枚举每个数,然后f减去那个数的权值,如果之后比0大,就说明那个数可取。汇和到i==0就是直接return 1)

    代码:

    #include <cstdio>
    #include <cstring>
    
    int dp[12][10000];
    int num[30];
    
    int getf(int x) {
        int ans = 0;
        int len = 0;
        while (x) {
            ans += (x%10)*(1<<(len));
            x/=10;
            len++;
        }
        return ans;
    }
    
    int dfs(int i, int f, bool isQuery) {
        if (f < 0) return 0;
        int &nowdp = dp[i][f];
        if (!isQuery && ~nowdp) return nowdp;
        if (i == 0) {
            return 1;
        }
        int end = isQuery?num[i]:9; /*这里不一样哦!*/
        int ans = 0;
        for (int j = 0; j <= end; j++) {
            int nextf = f-j*(1<<(i-1)); /*这里不一样哦!*/
            ans += dfs(i-1, nextf, isQuery && j==end);
        }
        if (!isQuery) nowdp = ans;
        return ans;
    }
    
    int cal(int a, int x) {
        int len = 0;
        if (x == 0) {
            num[++len] = 0;
        } else {
            while (x) {
                num[++len] = x%10;
                x/=10;
            }
        }
        return dfs(len, getf(a), true); /*这里不一样哦!*/
    }
    
    int main() {
        int t;
        scanf("%d", &t);
        memset(dp, -1, sizeof(dp));
        int cas = 1;
        while (t--) {
            printf("Case #%d: ", cas++);
            int a, b;
            scanf("%d%d", &a, &b);
            printf("%d
    ", cal(a,b));
        }
        return 0;
    }
  • 相关阅读:
    thinkphp 前后端分离
    git常用命令总结
    DIV常用属性大全
    shell编程学习之使用jq对json数据进行提取
    shell编程之if语句
    shell编程之变量赋值
    【总结】sqli-labs Less(1-35) 小结
    【总结】sqlmap常用命令
    【总结】kali(amd64)中安装nessus
    【总结】ettercap工具之DNS劫持
  • 原文地址:https://www.cnblogs.com/shinecheng/p/3600278.html
Copyright © 2011-2022 走看看