《算法竞赛-训练指南》第二章-2.5_UVa 11361
2013-08-11 16:43
309 查看
这道题目写了两天呀,好气愤呀。就是静不下心来,也不知道怎么回事。
也是这题目一直不让我过,改来改去都改不对。所以今天就什么都不想了,重写一边,开始也过不了,不过改了一下就过了。
气愤呀!
这道题目是个好题目,题目的大概意思是这样的:给你a,b,和k,问你在a-b之间有多少个这样的数字x,使得x%k == 0 并且 x的各个数字相加起来的和%k == 0。明显暴力是过不了的。这种题目第一步都是令f(x)表示0-x满足这些条件的数目,则题目就等于f(b) - f(a - 1)。
然后思考,这样的题目其实就类似关于数位的问题了。和数位dp就差不多是一个意思了,都是分解成一部分一部分的,然后再求解,分治的思想,把问题减小化,就能简化问题。
贴出成功的代码吧:(状态不佳呀~!)
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
using namespace std;
int a, b, MOD;
int pow10[11];
int m[11][91][91];
int mod(int n)
{
return (n % MOD + MOD) % MOD;
}
int f(int d, int m1, int m2)
{
if (d == 0)
{
return m1 == 0 && m2 == 0 ? 1 : 0;
}
int &ans = m[d][m1][m2];
if (ans >= 0)
{
return ans;
}
ans = 0;
for (int digit = 0; digit <= 9; digit++)
{
// cout << "d - 1 = " << d - 1 << endl;
// cout << "m1 - digit = " << m1 - digit << endl;
// cout << "m2 - digit * pow10[d - 1] = " << m2 - digit * pow10[d - 1] << endl;
ans += f(d - 1, mod(m1 - digit), mod(m2 - digit * pow10[d - 1]));
}
return ans;
}
int getSum(int x)
{
char digits[11];
sprintf(digits, "%d", x);
int ans = 0;
int sumd = 0;
int sums = 0;
int len = strlen(digits);
for (int i = 0; i < len; i++)
{
int R = len - i - 1;
int cnt = digits[i] - '0';
for (int digit = 0; digit < cnt; digit++)
{
// cout << "R = " << R << endl;
// cout << "mod(-sumd - digit) = " << mod(-sumd - digit) << endl;
// cout << "mod(-sums - digit * pow10[R]) = " << mod(-sums - digit * pow10[R]) << endl;
ans += f(R, mod(-sumd - digit), mod(-sums - digit * pow10[R]));
}
sumd += digits[i] - '0';
sums += (digits[i] - '0') * pow10[R];
}
return ans;
}
void init()
{
pow10[0] = 1;
for (int i = 1; i <= 9; i++)
{
pow10[i] = pow10[i - 1] * 10;
}
}
int main()
{
int T;
init();
scanf("%d", &T);
while (T--)
{
memset(m, -1, sizeof(m));
scanf("%d%d%d", &a, &b, &MOD);
if (MOD > 85)
{
printf("0\n");
}
else
{
// cout << "getSum(b + 1) = " << getSum(b + 1) << endl;
int ans = getSum(b + 1) - getSum(a);
printf("%d\n", ans);
}
}
// system("pause");
return 0;
}
也是这题目一直不让我过,改来改去都改不对。所以今天就什么都不想了,重写一边,开始也过不了,不过改了一下就过了。
气愤呀!
这道题目是个好题目,题目的大概意思是这样的:给你a,b,和k,问你在a-b之间有多少个这样的数字x,使得x%k == 0 并且 x的各个数字相加起来的和%k == 0。明显暴力是过不了的。这种题目第一步都是令f(x)表示0-x满足这些条件的数目,则题目就等于f(b) - f(a - 1)。
然后思考,这样的题目其实就类似关于数位的问题了。和数位dp就差不多是一个意思了,都是分解成一部分一部分的,然后再求解,分治的思想,把问题减小化,就能简化问题。
贴出成功的代码吧:(状态不佳呀~!)
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
using namespace std;
int a, b, MOD;
int pow10[11];
int m[11][91][91];
int mod(int n)
{
return (n % MOD + MOD) % MOD;
}
int f(int d, int m1, int m2)
{
if (d == 0)
{
return m1 == 0 && m2 == 0 ? 1 : 0;
}
int &ans = m[d][m1][m2];
if (ans >= 0)
{
return ans;
}
ans = 0;
for (int digit = 0; digit <= 9; digit++)
{
// cout << "d - 1 = " << d - 1 << endl;
// cout << "m1 - digit = " << m1 - digit << endl;
// cout << "m2 - digit * pow10[d - 1] = " << m2 - digit * pow10[d - 1] << endl;
ans += f(d - 1, mod(m1 - digit), mod(m2 - digit * pow10[d - 1]));
}
return ans;
}
int getSum(int x)
{
char digits[11];
sprintf(digits, "%d", x);
int ans = 0;
int sumd = 0;
int sums = 0;
int len = strlen(digits);
for (int i = 0; i < len; i++)
{
int R = len - i - 1;
int cnt = digits[i] - '0';
for (int digit = 0; digit < cnt; digit++)
{
// cout << "R = " << R << endl;
// cout << "mod(-sumd - digit) = " << mod(-sumd - digit) << endl;
// cout << "mod(-sums - digit * pow10[R]) = " << mod(-sums - digit * pow10[R]) << endl;
ans += f(R, mod(-sumd - digit), mod(-sums - digit * pow10[R]));
}
sumd += digits[i] - '0';
sums += (digits[i] - '0') * pow10[R];
}
return ans;
}
void init()
{
pow10[0] = 1;
for (int i = 1; i <= 9; i++)
{
pow10[i] = pow10[i - 1] * 10;
}
}
int main()
{
int T;
init();
scanf("%d", &T);
while (T--)
{
memset(m, -1, sizeof(m));
scanf("%d%d%d", &a, &b, &MOD);
if (MOD > 85)
{
printf("0\n");
}
else
{
// cout << "getSum(b + 1) = " << getSum(b + 1) << endl;
int ans = getSum(b + 1) - getSum(a);
printf("%d\n", ans);
}
}
// system("pause");
return 0;
}
相关文章推荐
- 《算法竞赛-训练指南》第二章-2.15_UVa 11722
- 《算法竞赛-训练指南》第二章-2.9_UVa 11426
- 《算法竞赛-训练指南》-第二章-2.16_UVa 11427
- 《算法竞赛-训练指南》第二章-2.14_UVa 11021
- 《算法竞赛-训练指南》-第二章-2.18_UVa 10294
- 《算法竞赛-训练指南》第二章-2.2_UVa 11401
- 《算法竞赛-训练指南》第二章-2.1_UVa 11538
- 《算法竞赛-训练指南》第二章-2.3_UVa 11806
- 《算法竞赛-训练指南》第二章-数论常用算法总结
- 《算法竞赛-训练指南》1.14-UVa 11520
- 《算法竞赛-训练指南》第二章-2.26_UVa 10341
- 《算法竞赛-训练指南》第一章-1.28_UVa 10891
- 《算法竞赛-训练指南》第五章-5.1_UVa 11624
- 《算法竞赛-训练指南》第一章-1.27-UVa 10635
- 《算法竞赛-训练指南》第二章-2.4-LA 3516
- 《算法竞赛-训练指南》第一章-1.9——UVa11210
- 《算法竞赛-训练指南》第二章-2.28_LA 3485(simpson)
- 《算法竞赛-训练指南》第一章-1.11——Uva 10795
- 《算法竞赛-训练指南》第一章-1.24-UVa 10755
- 《算法竞赛-训练指南》第一章-1.7——UVa 11464