zoukankan      html  css  js  c++  java
  • HDU 3652 & HDU 4734 数位DP 记忆化搜索

    数位dp中最重要的是要保证每一个dp能够唯一的表示状态。

    HDU 3652

    B-number

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 6311    Accepted Submission(s): 3648

    Problem Description

    A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string "13" and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task is to calculate how many wqb-numbers from 1 to n for a given integer n.

    Input

    Process till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).

    Output

    Print each answer in a single line.

    Sample Input

    13 100 200 1000

    Sample Output

    1 1 2 2

    Author

    wqb0039

    和昨天的题目类似,但是多加了一个判断条件,对13取模位0。这个只需要知道一个模运算的性质(a * b)mod n = (a mod n) * (b mod n) mod n。在10进制,对一个大数取模,只需要从高位到低位依次取模的值乘以10加上当前位取模即可。

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    using namespace std;
    
    int a[15];
    int dp[15][15][3];
    
    int dfs(int pre, int pos, int mod, int status, bool limit)
    {
        if(pos == 0) return status == 2 && mod == 0;
        if(!limit && dp[pos][mod][status] != -1) return dp[pos][mod][status];
        int up = limit ? a[pos] : 9;
        int ans = 0;
        for(int i = 0; i <= up; i++)
        {
            int nstatus;
            int nmod = (mod * 10 + i) % 13;
            if(status == 2 || pre == 1 && i == 3)
                nstatus = 2;
            else if(i == 1)
                nstatus = 1;
            else
                nstatus = 0;
            ans += dfs(i, pos-1, nmod, nstatus, limit && i == up);
        }
        if(!limit) dp[pos][mod][status] = ans;
        return ans;
    }
    
    int solve(int x)
    {
        int len = 0;
        while(x)
        {
            a[++len] = x%10;
            x /= 10;
        }
        a[len + 1] = 0;
        return dfs(-1, len, 0, 0, true);
    }
    
    int main()
    {
        int n;
        memset(dp, -1, sizeof(dp));
        while(scanf("%d", &n) == 1)
        {
            printf("%d
    ", solve(n));
        }
        return 0;
    }

    HDU 4734

    F(x)

    Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 5568    Accepted Submission(s): 2087

    Problem Description

    For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).

    Input

    The first line has a number T (T <= 10000) , indicating the number of test cases.
    For each test case, there are two numbers A and B (0 <= A,B < 109)

    Output

    For every case,you should output "Case #t: " at first, without quotes. The t is the case number starting from 1. Then output the answer.

    Sample Input

    3 0 100 1 10 5 100

    Sample Output

    Case #1: 1 Case #2: 2 Case #3: 13

    Source

    2013 ACM/ICPC Asia Regional Chengdu Online

    dp选取的状态表示方法一定要是对于每个样例都没有影响的。

    先贴上AC代码:

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    using namespace std;
    
    int a[15];
    int dp[15][200000];
    
    int dfs(int pos, int status, bool limit)
    {
        if(pos == 0) return status >= 0;
        if(status < 0) return 0;
        if(!limit && dp[pos][status] != -1) return dp[pos][status];
        int up = limit ? a[pos] : 9;
        int ans = 0;
        for(int i = 0; i <= up; i++)
        {
            ans += dfs(pos-1, status - i * (1 << (pos-1)), limit && up == i);
        }
        if(!limit) dp[pos][status] = ans;
        return ans;
    }
    
    int solve(int y, int x)
    {
        int k = 1;
        int weight = 0;
        while(y)
        {
            weight += (y%10) * (k);
            k *= 2;
            y /= 10;
        }
        int len = 0;
        while(x)
        {
            a[++len] = x%10;
            x /= 10;
        }
        a[len + 1] = 0;
        return dfs(len, weight, true);
    }
    
    int main()
    {
        int a, b, kase = 0, Q;
        scanf("%d", &Q);
        memset(dp, -1, sizeof(dp));
        while(Q--)
        {
            scanf("%d%d", &a, &b);
            printf("Case #%d: %d
    ", ++kase, solve(a,b));
        }
        return 0;
    }

    然后在贴上开始超时的代码,反思得到的经验就是,对于数位DP描述的选择,应该是对于问题的变化参数没有影响的。

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    using namespace std;
    
    int a[15];
    int dp[15][1 << 15];
    int weight;
    
    int dfs(int pos, int status, bool limit)
    {
        if(pos == 0) return status <= weight;
        if(!limit && dp[pos][status] != -1) return dp[pos][status];
        int up = limit ? a[pos] : 9;
        int ans = 0;
        for(int i = 0; i <= up; i++)
        {
            if(status + i * (1 << (pos-1)) > weight) continue;
            ans += dfs(pos-1, status + i * (1 << (pos-1)), limit && up == i);
        }
        if(!limit) dp[pos][status] = ans;
        return ans;
    }
    
    int solve(int y, int x)
    {
        int k = 0;
        memset(dp, -1, sizeof(dp));
        weight = 0;
        while(y)
        {
            weight += (y%10) * (1 << k);
            k++;
            y /= 10;
        }
        int len = 0;
        while(x)
        {
            a[++len] = x%10;
            x /= 10;
        }
        a[len + 1] = 0;
    
        return dfs(len, 0, true);
    }
    
    int main()
    {
        int a, b, kase = 0, Q;
        scanf("%d", &Q);
        while(Q--)
        {
            scanf("%d%d", &a, &b);
            printf("Case #%d: %d
    ", ++kase, solve(a,b));
        }
        return 0;
    }

     

     

    如果有错误,请指出,谢谢
  • 相关阅读:
    查询表结构
    centos使用docker发布.netcore3.0项目
    <五>输入输出模型的建立及登陆验证
    <二>引入NFine样式文件和登录界面
    <一>前言
    使用GUI工具高效构建你自己的Nuget包
    Angular开发者手册重点翻译之指令(一)
    WCF中操作的分界于调用顺序和会话的释放
    WCF中数据契约之已知类型的几种公开方式
    Singal Page App:使用Knockout和RequireJS创建高度模块化的单页应用引擎
  • 原文地址:https://www.cnblogs.com/Alruddy/p/7117979.html
Copyright © 2011-2022 走看看