您的位置:首页 > 其它

ACM: uva 11361 -&…

2016-05-19 23:29 363 查看
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 AB and K.
1
<= A <= B <
2^31 and
0<<B>K<10000.
Output

For each case, output the number of integers in the
range [AB] 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 <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;

}

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: