Investigating Div-Sum Property
An integer is divisible by 3 if the sum of its digits is also divisible by 3. For example, 3702 is divisible by 3 and 12(3+7+0+2) is also divisible by 3. This property also holds for the integer 9.
In this problem, we will investigate this property for other integers.
Input
The first line of input is an integer T(T<100) that indicates the number of test cases. Each case is a line containing 3 positive integers A, B and K. 1 <= A <= B < 2^31 and 0<K<10000.
Output
For each case, output the number of integers in the range [A, B] which is divisible by K and the sum of its digits is also divisible by K.
Sample Input
3
1 20 1
1 20 2
1 1000 4
Output for Sample Input
20
5
64
题意: 给出一个范围[a, b];, 判断这个范围内的数有多少个满足要求, 要求: 数能整除K, 每位数相加和
能整除K.
解题思路: (一道好题)
1. 给定一个范围求里面满足条件的数, 暴力枚举一般不可行. 设f(x)表示不超过x的非负整数中满足
条件的个数. 显然结果变成f(b)-f(a-1);
2. 问题变成怎么计算f(n)函数了, 可以用加法原理, 每一个数字段用一个固定前缀和不确定后缀表示.
例如: 123***, 123前缀是固定的, ***是可以任意的3个数字. 表示123000~123999.
3. 多阶段问题, 用记忆化搜索思路, 简化编程复杂性.
设状态dp[d][m1][m2]表示d个数字, m1表示个数字的和对K求余的数, m2表示整个数字对K求余的数.
状态方程: dp[d][m1][m2] = sum(dp[d-1][ (m1+x)%k ][ (m2+x*10^(d-1))%k ])
(x = 0, 1, 2, 3, ... , 9);
边界条件: if( d == 0 && (m1+x)%k == 0 && (m2+x*10^(d-1))%k ) return 1;
即: 当全部位数确定之后, 已经满足条件, 这个数字就是需要的数字, 结果+1;
代码:
#include
#include
#include
using namespace std;
#define MAX 105
typedef long long ll;
int a, b, k;
int dp[15][MAX][MAX], num[15];
ll pow[15];
void init()
{
ll x = 1;
for(int i = 0; i <= 10; ++i)
{
pow[i] = x;
x *= 10;
}
}
int DP(int d, int m1, int m2, int flag) //flag: 标记最高位 和区分状态
{
if( d == 0 ) return (m1 == 0 && m2 == 0);
if( !flag && dp[d][m1][m2] != -1) return dp[d][m1][m2];
int size = (flag ? num[d] : 9);
int ans = 0;
for(int x = 0; x <= size; ++x)
ans += DP(d-1, (m1+x)%k, (m2+pow[d-1]*x)%k, flag && x == size);
return flag ? ans : dp[d][m1][m2] = ans;
}
int solve(int a)
{
int len = 0;
while( a )
{
num[++len] = a;
a /= 10;
}
memset(dp, -1, sizeof(dp));
return DP(len, 0, 0, 1);
}
int main()
{
// freopen("input.txt", "r", stdin);
init();
int caseNum;
scanf("%d", &caseNum);
while(caseNum--)
{
scanf("%d %d %d", &a, &b, &k);
if(k >= 100) printf("0\n");
else printf("%d\n", solve(b) - solve(a-1));
}
return 0;
}