HDU 3652 B-number

数位DP

dp[i][j][k][m]表示最高位为i,数字j在首位,之前是否出现过13,余数是m的情况下的个数

代码有详细注释,做完这题,感觉逐渐了解了数位DP

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
#include <string>
using namespace std;

int dp[15][15][5][15];
int tot,n;
int p[20];

bool cheak(int a,int b,int c,int d)
{
    int res=a;
    for(int i=1;i<=b-1;i++) res=((res*10)%13);
    if((res+c)%13==d) return 1;
    return 0;
}

bool check2(int a,int b)
{
    int num=0;
    for(int i=tot;i>=1;i--)
    {
        if(i>=a+1) num=num*10+p[i];
        else num=num*10;
    }
    if((num%13+b)%13==0) return 1;
    return 0;
}

void init()
{
    memset(dp,0,sizeof dp);

    for(int j=0;j<=9;j++) dp[1][j][0][j]=1;

    for(int i=2;i<=10;i++)
    {
        for(int j=0;j<=9;j++)
        {
            for(int k=0;k<=1;k++)
            {
                for(int l=0;l<=12;l++)
                {
                    int sum=0;
                    if(k==0)//推到第i位的时候都没有13
                    {
                        for(int s=0;s<=9;s++)//枚举i-1位是多少
                        {
                            if(j==1&&s==3) continue;
                            for(int m=0;m<=12;m++)//枚举余数
                                if(cheak(j,i,m,l))
                                    sum=sum+dp[i-1][s][0][m];
                        }
                        dp[i][j][k][l]=sum;
                    }
                    else if(k==1)//推到第i位的时候有13,可能之前就有13,也可能i位和i-1位产生了13
                    {
                        //之前就有13
                        for(int s=0;s<=9;s++)
                            for(int m=0;m<=12;m++)//枚举余数
                                if(cheak(j,i,m,l))
                                    sum=sum+dp[i-1][s][1][m];

                        //i位和i-1位产生了13
                        for(int s=0;s<=9;s++)
                            if(j==1&&s==3)//这一位是1,上一位是3
                                for(int m=0;m<=12;m++)//枚举余数
                                    if(cheak(j,i,m,l))
                                        sum=sum+dp[i-1][s][0][m];//从之前没有13的情况推导过来
                        dp[i][j][k][l]=sum;
                    }
                }
            }
        }
    }
}

int f(int x)
{
    tot=1;
    while(x)
    {
        p[tot++]=(x%10);
        x=x/10;
    }
    tot--;

    int res=0;

    //计算位数比tot小的总和
    for(int i=1;i<tot;i++)
    {
        for(int j=1;j<=9;j++)
        {
            res=res+dp[i][j][1][0];
        }
    }

    //计算位数为tot,但首位比x首位小的数量总和
    for(int i=1;i<p[tot];i++) res=res+dp[tot][i][1][0];

    //计算剩余部分
    bool flag=0;
    for(int i=tot-1;i>=1;i--)
    {
        for(int j=0;j<p[i];j++)
        {
            if(flag==0)
            {
                if(j==3&&p[i+1]==1)
                {
                    for(int m=0;m<=12;m++)
                    {
                        if(check2(i,m))
                        {
                            res=res+dp[i][j][0][m];
                            res=res+dp[i][j][1][m];
                        }
                    }
                }
                else
                {
                    for(int m=0;m<=12;m++)
                    {
                        if(check2(i,m))
                        {
                            res=res+dp[i][j][1][m];
                        }
                    }
                }
            }
            else if(flag==1)
            {
                for(int m=0;m<=12;m++)
                {
                    if(check2(i,m))
                    {
                        res=res+dp[i][j][0][m];
                        res=res+dp[i][j][1][m];
                    }
                }
            }
        }
        if(p[i]==3&&p[i+1]==1) flag=1;//表示之前已经出现过13了
    }

    return res;
}

int main()
{
    init();
    while(~scanf("%d",&n))
        printf("%d\n",f(n+1));
    return 0;
}
时间: 2024-10-12 19:16:57

HDU 3652 B-number的相关文章

【HDU 3652】 B-number (数位DP)

B-number 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

HDU 4937 Lucky Number 搜索

题意: 给你一个数,求在多少种不同的进制下这个数每一位都是3.4.5.6中的一个. 思路: 搜索.枚举这个数在任意进制下的表示,判断是否合法.当数字只有3.4.5.6时,必定有无穷种. 因为数字太大,所以直接枚举必定会超时. 下面有两种剪枝的方法: 1. 先枚举最后一位的情况. 假设数字n在base进制下表示为 a[n]...a[0],即 n = a[0] + a[1]*base^1 + ... + a[n]*base^n. 则 n - a[0] = a[1]*base^1 + ... + a[

hdu 4937 Lucky Number ( 进制转换+枚举 )

题意: 有一个数n,问有多少个进制x(基数)使得n转换为x进制后的数字中只有3.4.5.6四个数. 算法: 对于只有一位数的情况,显然3.4.5.6都应该输出-1. 如果有2位数,假设这2位中高位为a,低位为b,进制为base,则 n = a * base + b,解一元一次方程即可. 如果有3位数,假设这3为从高到低分别为a.b.c,进制为base,则 n = a * base * base + b * base + c,即一元二次方程即可. 如果位数>= 4,可以暴力枚举进制数.base>

hdu 2665 Kth number(划分树)

Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4602 Accepted Submission(s): 1468 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first l

hdu 3006 The Number of set(思维+壮压DP)

The Number of set Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1056    Accepted Submission(s): 655 Problem Description Given you n sets.All positive integers in sets are not less than 1 and

hdu 5787 K-wolf Number 数位dp

数位DP 神模板 详解 为了方便自己参看,我把代码复制过来吧 // pos = 当前处理的位置(一般从高位到低位) // pre = 上一个位的数字(更高的那一位) // status = 要达到的状态,如果为1则可以认为找到了答案,到时候用来返回, // 给计数器+1. // limit = 是否受限,也即当前处理这位能否随便取值.如567,当前处理6这位, // 如果前面取的是4,则当前这位可以取0-9.如果前面取的5,那么当前 // 这位就不能随便取,不然会超出这个数的范围,所以如果前面取

枚举 + 进制转换 --- hdu 4937 Lucky Number

Lucky Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 294    Accepted Submission(s): 49 Problem Description “Ladies and Gentlemen, It’s show time! ” “A thief is a creative artist who ta

HDU 4937 Lucky Number 乱搞 + 优化

题意:给你一个数n (1- 1e12),问你有多少种进制使得 这个数用这个进制表示只有 3 . 4 . 5. 6 这4个数 解题思路:这里本来是想要枚举的,发现数太大了,这里利用到了一中很巧妙的优化方法,将 2位 和3位转化成为 一元一次 和一元二次方程,就可以有很大的优化,然后只需要枚举到7000即可 1 // File Name: 1003.cpp 2 // Author: darkdream 3 // Created Time: 2014年08月12日 星期二 12时01分53秒 4 5

HDU 4937 Lucky Number (数学,进制转换)

题目 参考自博客:http://blog.csdn.net/a601025382s/article/details/38517783 //string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last); //把[first0,last0)之间的部分替换成[first,last)之间的字符串 /* 题意: 我们将3,4,5,6认为是幸运数字.给定一个十进制数n. 现在可以讲起任意转

HDU 1018 Big Number 数学题解

Problem Description In many applications very large integers numbers are required. Some of these applications are using keys for secure transmission of data, encryption, etc. In this problem you are given a number, you have to determine the number of