题意:
在给定范围内(9*10^18)求出有多少个数满足被所有非零位的数整除。
思路:
可以先想到如果被所有非零位的数整除,那么就会被他们的lcm整除。
而lcm(1,2...9) = 2520.
即2520可以整除1 - 9中任意组合的lcm。
所以可以用%2520的值表示状态,最后用最终状态值%lcm(x1...xn),判断是否为0。
1 - 9lcm组合的情况数由 2^3*3^2*5*7可以得出为:4*3*2*2 = 48 ,预处理提取出来。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MOD = 2520; int t; int bit[20], index[MOD+5]; ll l, r; ll dp[20][MOD][50]; int gcd(int x, int y) { return y==0?x:gcd(y, x%y); } int lcm(int x, int y) { return x/gcd(x, y)*y; } void init() { int cnt = 0; memset(dp, -1, sizeof(dp)); for(int i = 1; i <= MOD; i++) if(!(MOD % i)) index[i] = cnt++; } ll dfs(int pos, int presum, int prelcm, bool limit) { if(pos == -1) return presum%prelcm==0; if((!limit) && dp[pos][presum][index[prelcm]] != -1) return dp[pos][presum][index[prelcm]]; int up = limit?bit[pos]:9; ll res = 0; for(int i = 0; i <= up; i++) { int nowsum = (presum*10+i)%MOD; int nowlcm = i==0?prelcm:lcm(prelcm, i); res += dfs(pos-1, nowsum, nowlcm, limit && i == bit[pos]); } if(!limit) dp[pos][presum][index[prelcm]] = res; return res; } ll solve(ll x) { int pos = 0; while(x) { bit[pos++] = x%10; x /= 10; } return dfs(pos-1, 0, 1, true); } int main() { init(); scanf("%d", &t); while(t--) { scanf("%I64d%I64d", &l, &r); printf("%I64d\n", solve(r) - solve(l-1)); } }