ACM: uva 11361 -&…

来源:互联网 发布:网络延迟多少ms算正常 编辑:程序博客网 时间:2024/06/05 04:23

Investigating Div-Sum Property

An integer is divisible by 3 if the sum of its digits is alsodivisible 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 integer9.

In this problem, we will investigate this property for otherintegers.

Input

The first line of input is aninteger T(T<100) thatindicates the number of test cases. Each case is a line containing3 positiveintegers AB and K.1<= A <= B <2^31 and0<<B>K<10000.

Output

For each case, output the number of integers in therange [AB] which is divisibleby K and the sum of itsdigits 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 ) return1;

        即:当全部位数确定之后, 已经满足条件, 这个数字就是需要的数字, 结果+1;

 

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
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;
}

 

0 0
原创粉丝点击