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
**************************/


你可能感兴趣的:(codeforce 55D Beautiful numbers)