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 A, B and K.
1
<= A <= B <
2^31 and
0<<B>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 <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;
}
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<<B>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 <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;
}
相关文章推荐
- ACM: uva 1362 -&n…
- Android Studio JNI编程
- ACM: uva 11174 - Stand in a Line
- ACM: uva 11375 - Matches
- ACM: uva 11401 - Triangle Counti…
- ACM: uva 11538 - Chess Queen
- ACM: uva 10534 - Wavio Sequence
- ACM: uva 1424 - Salesmen
- web新内容
- 深入分析 Java 中的中文编码问题(1)
- ACM: uva 11584 -
- ACM: uva 1468 - Restaurant
- ACM: poj 3972 -&n…
- jquery 1.6 后 checkbox 使用attr("checked"),undefined.
- ACM: poj 2786 -&n…
- ACM: uva 1432 -&n…
- ACM: uva 1451 - Average
- ACM: uva 10391 - Compound Words
- ACM: uva 10763 -&…
- ACM: uva 10125 - Sumsets