CF 55 D. Beautiful numbers
D. Beautiful numbers
题意:
求[L,R]中多少个数字可以整除它们的每一位上的数字。
分析:
要求模一些数字等于0等价于模它们的lcm等于0,所以可以记录当前出现的数字的lcm,最后判断组成的数字是否模lcm等于0。
但是这个数字太大记录不下。根据一个性质a%b=(a%kb)%b,所以可以记录当前的数字模2520的值,最后模一下lcm。
这样的状态是$20 \times 2520 \times 2520$的,状态太大了,考虑如何缩小空间。因为1~9的lcm只能是50个左右,所以可以将第三维压成50。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> using namespace std; typedef long long LL; inline LL read() { LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 2520; LL dp[30][50][N + 10]; int num[50]={0,1,2,3,4,5,6,7,8,9,10,12,14,15,18,20,21,24,28,30,35,36,40,42,45,56,60,63,70,72,84,90,105,120,126,140,168,180,210,252,280,315,360,420,504,630,840,1260,2520}; int a[30], pos[N + 10]; int gcd(int a,int b) { return b == 0 ? a : gcd(b, a % b); } int getlcm(int a,int b) { return a * b / gcd(a, b); } LL dfs(int p,int lcm,int now,bool lim) { if (p == 0) return lcm && now % num[lcm] == 0; if (!lim && ~dp[p][lcm][now]) return dp[p][lcm][now]; int u = lim ? a[p] : 9; LL ans = 0; for (int i = 0; i <= u; ++i) { int t = lcm ? pos[getlcm(num[lcm], max(i, 1))] : i; ans += dfs(p - 1, t, (now * 10 + i) % N, lim && i == u); } if (!lim) dp[p][lcm][now] = ans; return ans; } LL solve(LL x) { if (x <= 0) return 0; int pos = 0; while (x) { a[++pos] = x % 10; x /= 10; } return dfs(pos, 0, 0, 1); } int main() { memset(dp, -1, sizeof(dp)); for (int i = 0; i < 49; ++i) pos[num[i]] = i; for (int T = read(); T --; ) { LL x = read(), y = read(); cout << (solve(y) - solve(x - 1)) << "\n"; } return 0; }