zoukankan      html  css  js  c++  java
  • 数位DP入门之hdu 3652 B-number

    hdu 3652 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 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

    参考了Qiuqiqiu特别是递推中使用的加法来mod(开始我使用的是减法,很难看)下面是我的总结;
    思路:
    1. 和3555Bomb一样,要含有13,可知第二维要表示是否含13,首位是否为3以及已经含13三种,还有一个就是整除问题;拓展一维来表示余数,其余的一样操作;当最高位为0时,表示所有小于n位数的数符合的情况,所以在高位相同,且高位中已经含有 ‘13’时直接加不含 ‘13’的个数即可;
    2. **当第i位为1时,由求的是小于n的所有符合数可知在模拟第i位时只会模拟到0,那么加的只是f[i-1][2][]的所有符合的情况;那这个1一定要浪费吗?当你是取i-1位从0~9时,答案是的。但是当只要存在13时(整除在三维中模拟),还要看后一位是否大于3….(特别的地方);

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,n) for(int (i) = 0;i < (n);i++)
    int f[15][3][13];
    int bit[12];
    void init()
    {
        memset(f,0,sizeof(f));
        bit[1] = 1;
        for(int i = 2;i < 11;i++) bit[i] = bit[i-1]*10%13;
        f[0][0][0] = 1;
        for(int i = 0;i <= 10;i++)
        for(int k = 0;k < 13;k++){//直接按照需要的数来递推
            for(int j = 0;j <= 9;j++)
                f[i+1][0][(k+j*bit[i+1])%13] += f[i][0][k];
            f[i+1][0][(k+bit[i+1])%13] -= f[i][1][k];
            f[i+1][1][(k+bit[i+1]*3)%13] += f[i][0][k];//指定来加~~;
            f[i+1][2][(k+bit[i+1])%13] += f[i][1][k];
            for(int j = 0;j <= 9;j++)
                f[i+1][2][(k+bit[i+1]*j)%13] += f[i][2][k];
        }
    }
    int query(int n)
    {
        int d[15]={},tot = 0;
        while(n){
            d[++tot] = n % 10;
            n /= 10;
        }
        int ans = 0,mod = 0,flag = 0;
        for(int i = tot;i > 0;mod = (mod + d[i]*bit[i])%13,i--){
            for(int j = 0;j < d[i];j++)
                ans += f[i-1][2][(13 - (mod + j*bit[i])%13)%13];
            if(flag){
                for(int k = 0;k < d[i];k++){
                    ans += f[i-1][0][(13 - (mod + k * bit[i])%13)%13];
                }
                continue;
            }
            if(d[i] > 1) ans += f[i-1][1][(13 - (mod + bit[i])%13)%13];
            if(d[i+1] == 1 && d[i] > 3) ans += f[i][1][(13-mod)%13];
            if(d[i+1] == 1 && d[i] == 3) flag = 1;
        }
        return ans;
    }
    int main()
    {
        init();
        int n;
        while(scanf("%d",&n) == 1){
            printf("%d
    ",query(n+1));
        }
    }
    View Code
     
  • 相关阅读:
    webpack基础
    LeetCode232. 用栈实现队列做题笔记
    mysql 时间加减一个月
    leetcode 1381. 设计一个支持增量操作的栈 思路与算法
    LeetCode 141. 环形链表 做题笔记
    leetcode 707. 设计链表 做题笔记
    leetcode 876. 链表的中间结点 做题笔记
    leetcode 143. 重排链表 做题笔记
    leetcode 1365. 有多少小于当前数字的数字 做题笔记
    LeetCode1360. 日期之间隔几天 做题笔记
  • 原文地址:https://www.cnblogs.com/hxer/p/5185133.html
Copyright © 2011-2022 走看看