题意:求出l到r中,能整除自己各非0位的和的数有多少个。
转换一下,就相当于求整除自己各非0位的最小公倍数,然后1到9公倍数范围是1到2520,会爆内存,考虑离散化。
转移过程有两种,一种是非0的,一种是数位是0的,是0的话最小公倍数不变,否则最小公倍数跟新的数求一下最小公倍数。
然后mod要一直取余2520,防止数组越界。
//多少个数能够整除自身各位数
//相当于 多少个数能够整除自身各位数的最小公倍数
#include <iostream>
#include <algorithm>
#include <string.h>
#include <set>
using namespace std;
__int64 f[20][2521][50];
__int64 num[] = { 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[20];
__int64 gcd(__int64 a, __int64 b)
{
return b == 0 ? a : gcd(b, a % b);
}
__int64 lc(__int64 a, __int64 b)
{
return a * b / gcd(a, b);
}
__int64 dp(__int64 pos, __int64 mod, __int64 lcm, bool flag)
{
if (pos == 0) return mod % lcm == 0;
__int64 tmp = lower_bound(num, num + 48, lcm) - num;
if (flag && f[pos][mod][tmp] != -1) return f[pos][mod][tmp];
int x = flag ? 9 : a[pos];
__int64 ans = 0;
for (int i = 0; i <= x; i++)
{
if (i == 0) ans += dp(pos - 1, (mod * 10 + i) % 2520, lcm, flag || i < x);
else ans += dp(pos - 1, (mod * 10 + i) % 2520, lc(lcm, i), flag || i < x);
}
if (flag) f[pos][mod][tmp] = ans;
return ans;
}
__int64 cul(__int64 x)
{
int pos = 0;
while (x)
{
a[++pos] = x % 10;
x /= 10;
}
return dp(pos, 0, 1, false);
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
memset(f, -1, sizeof(f));
while (t--)
{
__int64 l, r;
cin >> l >> r;
cout << cul(r) - cul(l - 1) << endl;
}
}搞出num数组的方法,用下面这个程序输出的结果往上面拷贝
#include <iostream>
#include <algorithm>
#include <string.h>
#include <set>
using namespace std;
set <int> st;
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
int lc(int a, int b)
{
return a * b / gcd(a, b);
}
int main()
{
for (int i = 0; i < (1 << 9); i++)
{
int ans = 1;
int ii = i;
for (int j = 1; j <= 9; j++)
{
if (ii & 1) ans = lc(ans, j);
ii >>= 1;
}
st.insert(ans);
}
int i = 0;
for (set<int>::iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << ",";
i++;
if (i % 10 == 0) cout << endl;
}
}


京公网安备 11010502036488号