您的位置:首页 > 其它

codeforces 55D. Beautiful numbers 数位dp

2015-12-10 23:51 363 查看
题目链接

一个数, 他的所有位上的数都可以被这个数整除, 求出范围内满足条件的数的个数。

dp[i][j][k], i表示第i位, j表示前几位的lcm是几, k表示这个数mod2520, 2520是1-9之间数的lcm。 然后这样数组就要开成20*2520*2520, 太大了, 所以我们将lcm离散, 因为1-9的lcm根本没有那么多的数, 实际上只有48个。

这题好难想...

#include<bits/stdc++.h>
using namespace std;
#define mem1(a) memset(a, -1, sizeof(a))
#define ll long long
int digit[30], len, idx[3000];
ll dp[30][2522][50];
int gcd(int a, int b) {
return b==0?a:gcd(b, a%b);
}
int get_lcm(int a, int b) {
return a/gcd(a, b)*b;
}
void init() {
int num = 0;
for(int i = 1; i<=2520; i++) {
if(2520%i==0)
idx[i] = num++;
}
mem1(dp);
}
ll dfs(int len, int lcm, int num, int f) {
if(!len) {
return num%lcm==0;
}
if(!f&&dp[len][num][idx[lcm]]!=-1)
return dp[len][num][idx[lcm]];
ll ret = 0, maxx = f?digit[len]:9;
for(int i = 0; i<=maxx; i++) {
if(i == 0) {
ret += dfs(len-1, lcm, (num*10)%2520, f&&i==maxx);
} else {
int tmp = get_lcm(lcm, i);
ret += dfs(len-1, tmp, (num*10+i)%2520, f&&i==maxx);
}
}
if(!f)
return dp[len][num][idx[lcm]] = ret;
return ret;
}
ll cal(ll n) {
len = 0;
while(n) {
digit[++len] = n%10;
n/=10;
}
return dfs(len, 1, 0, 1);
}
int main()
{
ll a, b, t;
init();
cin>>t;
while(t--) {
scanf("%I64d%I64d", &a, &b);
printf("%I64d\n", cal(b)-cal(a-1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: