题意大概是,判断一个正整数区间内有多少个整数能被它自身的每一个非零的数字整除。
因为每一个位置上的整数集s = {0,1,2,3,4,5,6,7,8,9} lcm(s) = 2520
现在有一个整数t是由s中一个或者多个数字构成的,记为abcde,显然t = a*10^4+b*10^3+c*10^2+d*10^1+e
要使得t能被a,b,c,d,e整除,必然有t % lcm(a,b,c,d,e) = 0 因为a,b,c,d,e去重之后一定是s的一个子集,所以lcm(s)一定是lcm(a,b,c,d,e)的倍数,所以只要
t % lcm(s) % lcm(a,b,c,d,e) = 0 满足答案。
一开始不知道这道题应该怎么存储状态,因为随着数字的变化,这个lcm(a,b,c,d,e)是会改变的,没法直接存储对lcm(a,b,c,d,e)的余数,但是lcm(s)是不变的,所以我们只要存储lcm(s)的余数和lcm(a,b,c,d,e)就好了,因为一共就九个数字,lcm一共只有48个,所以复杂度为lcm(s)*48*maxlen
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <set> #include <queue> #include <stack> using namespace std; typedef long long LL; const int maxn = 20; const int mod = 2520; int lim[maxn],len; LL f[maxn][50][mod]; map<int,int> st; int ccon[(1 << 10)],clcm[50]; void getlim(LL num) { len = 0; memset(lim,0,sizeof(lim)); while(num) { lim[len++] = num % 10; num /= 10; } } LL gcd(LL a,LL b) { return b == 0 ? a : gcd(b,a % b); } LL lcm(LL a,LL b) { return a / gcd(a,b) * b; } void init() { int cnt = 0; for(int i = 1;i < (1 << 10);i++) { int nlcm = 1; for(int j = 1;j <= 9;j++) if(i & (1 << j)) { nlcm = lcm(nlcm,j); } if(!st.count(nlcm)) { st[nlcm] = cnt; clcm[cnt++] = nlcm; } ccon[i] = st[nlcm]; } ccon[0] = -1; } LL dfs(int now,int mask,int rest,int bound) { if(now == 0) { if(mask <= 1) return 0; return rest % clcm[ccon[mask]] == 0; } LL ¬e = f[now][ccon[mask]][rest]; if(!bound && note != -1 && mask > 1) return note; int m = bound ? lim[now - 1] : 9; LL ret = 0; for(int i = 0;i <= m;i++) { ret += dfs(now - 1,mask | (1 << i),(rest * 10 + i) % mod,i == m && bound); } if(!bound && mask > 1) note = ret; return ret; } LL solve(LL num) { getlim(num); return dfs(len,0,0,1); } int main() { memset(f,-1,sizeof(f)); init(); int T; cin >> T; while(T--) { LL a,b; cin >> a >> b; cout << solve(b) - solve(a - 1) << endl; } return 0; }
CodeForces 55D Beautiful numbers 数位DP+数学
时间: 2024-10-11 06:29:46