CodeForces - 55D Beautiful numbers 数位dp

题目链接:https://cn.vjudge.net/problem/CodeForces-55D#author=0

题意:有多少数,满足是每一位数的倍数

题解:1-9的最小公倍数为2520,1-9最小公倍数的形成的种数48种,所以对于每个形成的lcm需要重新编号一下

dp[ i ][ j ][ k ] 表示还剩 i位,前面的余数是j,lcm是k的数目

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[22][2522][55], f[2522];
int w[22], len;
int getlcm(int x, int y) {
	if(!y) return x;
	return x * y / __gcd(x, y);
} 
ll dfs(int pos, int limit, int pre, int lcm) {
	if(pos < 0) return pre % lcm == 0;
	if(!limit && dp[pos][pre][f[lcm]] != -1) return dp[pos][pre][f[lcm]];
	int up = limit ? w[pos] : 9;
	ll res = 0;
	for(int i = 0; i <= up; i++) {
		res += dfs(pos - 1, limit && i == up, (pre * 10 + i) % 2520, getlcm(lcm, i));
	}
	if(!limit) dp[pos][pre][f[lcm]] = res;
	return res;
}
ll solve(ll x) {
	len = 0;
	while(x) {
		w[len++] = x % 10;
		x /= 10;
	}
	return dfs(len - 1, 1, 0, 1);
}
int main() {
	ll l, r = 1;
	for(int i = 1; i <= 10; i++) {
		r = getlcm(i, r);
	}
	// 2520
	l = 0;
	int x;
	// 48
	for(int i = 1; i < 1024; i++) {
		r = 1;
		x = i;
		for(int j = 1; x && j < 10; j++, x >>= 1)
			if(x & 1)
				r = getlcm(r, j);
		if(!f[r]) f[r] = ++l;
	}
	memset(dp, -1, sizeof(dp));
	int T;
	scanf("%d", &T);
	while(T--) {
		scanf("%I64d %I64d", &l, &r);
		printf("%I64d\n", solve(r) - solve(l - 1));
	}
		
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值