zoukankan      html  css  js  c++  java
  • HDU 4389 X mod f(x)

    题意:求[A,B]内有多少个数,满足x % f(x) == 0。


    解法:数位DP。转化为ans = solve(b) - solve(a - 1)。设dp[i][sum][mod][r]表示长度为i,各位和为sum,模mod余r的数的个数。

    当在数字后面新添加一位j时,则有dp[i + 1][sum + j][mod][(r * 10 + j) % mod] += dp[i][sum][mod][r]。

    当一个数比n小时,一定是因为从某一位开始出现了当前位的数字比n当前位数字小的情况,从高到低枚举这种情况出现的位数,枚举这位的数字,枚举所有数字的和,即模,满足等式(num + j * 10 ^ i + r) % mod == 0时即符合情况,num为前i位确定时的数值。

    for i len...1

    for j 0...digit[i]

    for mod 1...81

    for r 0...mod - 1

    if (当前已确定位数值 + j * 10 ^ i + r) % mod == 0

    ans += dp[i - 1][mod - 前i位和 - j][mod][r]


    代码:

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    #include<string>
    #include<string.h>
    #include<math.h>
    #include<limits.h>
    #include<time.h>
    #include<stdlib.h>
    #include<map>
    #include<queue>
    #include<set>
    #include<stack>
    #include<vector>
    #define LL long long
    using namespace std;
    int dp[12][85][85][85] = {0};
    int f(int x)
    {
        if(x == 0) return 0;
        return f(x / 10) + x % 10;
    }
    void init()//初始化
    {
        for(int i = 0; i < 85; i++)
            dp[0][0][i][0] = 1;
        for(int i = 0; i < 9; i++)
            for(int j = 0; j < 85; j++)
                for(int k = 0; k < 85; k++)
                    for(int l = 0; l < k; l++)
                        for(int m = 0; m < 10 && m + j < 85; m++)
                            dp[i + 1][j + m][k][(l * 10 + m) % k] += dp[i][j][k][l];
    }
    int solve(int x)
    {
        int ans = 0;
        if(x && (x % f(x) == 0))
            ans++;
        int digit[15] = {0};
        int ten[15] = {0, 1, 0};
        for(int i = 2; i <= 10; i++)
            ten[i] = ten[i - 1] * 10;
        int len = 1;
        int tmp = x;
        while(tmp)
        {
            digit[len++] = tmp % 10;
            tmp /= 10;
        }
        int sum = 0;
        int num = 0;
        for(int i = len - 1; i >= 1; i--)//枚举位数
        {
            for(int j = 0; j < digit[i]; j++)
                for(int k = 1; k < 85; k++)
                    for(int l = 0; l < k; l++)
                        if((k >= (sum + j)) && ((num + j * ten[i] + l) % k == 0))
                            ans += dp[i - 1][k - sum - j][k][l];
            sum += digit[i];
            num += digit[i] * ten[i];
        }
        return ans;
    }
    int main()
    {
        init();
        int T;
        while(~scanf("%d", &T))
        {
            int cnt = 1;
            while(T--)
            {
                int a, b;
                scanf("%d%d", &a, &b);
                printf("Case %d: %d
    ", cnt++, solve(b) - solve(a - 1));
            }
        }
    }
    


  • 相关阅读:
    A/B-test
    LDA概率主题模型
    减肥经验帖
    wide and deep
    利用责任链模式设计一个拦截器
    分享几个 SpringBoot 实用的小技巧
    「造个轮子」——cicada 设计一个配置模块
    「造个轮子」——cicada 源码分析
    「造个轮子」——cicada(轻量级 WEB 框架)
    强如 Disruptor 也发生内存溢出?
  • 原文地址:https://www.cnblogs.com/Apro/p/4303981.html
Copyright © 2011-2022 走看看