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));
        }
    }
}


原文地址:https://www.cnblogs.com/Apro/p/4303981.html