codeforce 55D Beautiful numbers

D. Beautiful numbers
time limit per test:4 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output

Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with this and just count the quantity of beautiful numbers in given ranges.
Input

The first line of the input contains the number of cases t (1 ≤ t ≤ 10). Each of the next t lines contains two natural numbers li and ri (1 ≤ li ≤ ri ≤ 9 · 1018).

Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered to use cin (also you may use %I64d).
Output

Output should contain t numbers — answers to the queries, one number per line — quantities of beautiful numbers in given intervals (from li to ri, inclusively).
Sample test(s)
Input
1
1 9
Output
9
Input
1
12 15
Output

2


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int num[20], ln;
__int64 f[20][2521][50];
int hash[2521];

void swap(int &a, int &b){
	int t = a;
	a = b; 
	b = t;
}

int gcd(int a, int b){
	int c;
	while(b){
		c = a % b;
		a = b;
		b = c;
	}
	return a;
}

int Lcm(int a, int b){
//	printf("Lcm %d, %d\n", a, b);	
	if (a < b) swap(a, b);
	if (b == 0) return a;
	return a * b / gcd(a, b);
}

__int64 dfs(int i, int mod, int mark, bool flag){
	int p, high;
	__int64 ret;
	
//	printf("dfs(%d, %d, %d, %d)\n", i, mod, mark, flag);
	
	if (i <= 0) return (mod % mark == 0);
	if (!flag && ~f[i][mod][hash[mark]]) return f[i][mod][hash[mark]];
	
	high = flag ? num[i] : 9;
	ret = 0;
	for (p = 0; p <= high; p++){
//		printf("p = %d\n", p);
		ret += dfs(i - 1, (mod * 10 + p) % 2520, Lcm(mark, p), flag && (p == high));
	}
	if (!flag) f[i][mod][hash[mark]] = ret;
	return ret;
}


void trans(__int64 n){
	ln = 0;
	while(n){
		num[++ln] = n % 10;
		n = n / 10;
	}
}

__int64 calc(__int64 n){
	trans(n);
	return dfs(ln, 0, 1, true);
}

void init(){
	int i, j, k, l, cnt = 0;
	memset(f, 0xff, sizeof(f));
	hash[0] = 0;
	for (i = 1; i < 10; i *= 2)
		for (j = 1; j < 10; j *= 3)
			for (k = 1; k < 10; k *= 5)
				for (l = 1; l < 10; l *= 7){
					hash[i * j * k * l] = ++cnt;
				}
}

int main(){
	__int64 L, R;
	int T;
	init();
	scanf("%d", &T);
	while(T--){
		scanf("%I64d %I64d", &L, &R);
		printf("%I64d\n", calc(R) - calc(L - 1));
	}
	return 0;
}

/**************************
按位dp
表示看解题报告后写的。。见http://hi.baidu.com/%B1%BFС%BA%A2_shw/blog/item/a30e5c230dffdfe7d6cae200.html
开始时想不通怎么判是否整除所有位的数,想存模2..9的所有余数的情况。。。
其实根本没必要,我们希望知道一个数n是否整除LCM{n的每位数}(记做mark),而LCM{2...9} = 2520的,一定能整除mark,
所以 mark | n <=> mark | (n % 2520)
或者说 n % mark = (k * 2520 + k1) % mark = k1 % mark 
于是记录下模2520和当前lcm(程序中为mark),判断下模2520余出来的那部分能否整除当前lcm即可
为方便存储,mark一共只有4 * 3 * 2 * 2 = 48种(分别代表2,3,5,7在小于10可能取到的幂数),hash一下节省空间

话说这样的空间消耗,真怕会爆掉的。。。但在codeforce里慢慢地跑了300ms+过了Accepted。。。
还有更进一步优化,详见http://codeforces.ru/blog/entry/1109?locale=en
**************************/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值