标签:
题目大意:
美丽数: 这个数字能整除他自己各个位上的非零数。
给你一个区间问其中的美丽数有多少个。
分析:dp[位数][各个位数上的最小公倍数][对2520取余后的值] = 满足条件数的个数
1. 我所得到的数字对 所有位数上的数字的最小公倍数取余 如果==0 说明是合法的
2. 1-9的最小公倍数是2520 所以我的到的数字先对2520取余,再对其各个位数上的数字取余,一样可以得到相同的结果。
3. 因为我们要开 dp[20][2520][2520] 的数组是要超内存的 所以我们要将 最后一维 给他离散化一下, 最后结果只有50个数字。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; #define MOD 2520 LL dp[20][MOD][52]; int bit[20], index[MOD+10]; void init() { int i, num = 0; memset(dp, -1, sizeof(dp)); for(i=1; i<=MOD; i++) { if( MOD%i == 0) index[i] = num ++; } } int gcd(int a,int b) { return b == 0? a : gcd(b, a%b); } int lcm(int a,int b) { return a/gcd(a,b)*b; } LL dfs(int pos,int preSum,int preLcm,int flag) { if(pos == -1) { return preSum%preLcm == 0; } if(!flag && dp[pos][preSum][index[preLcm]] != -1) return dp[pos][preSum][index[preLcm]]; LL ans = 0; int end = flag?bit[pos]:9; for(int i=0; i<=end; i++) { int nowSum = (preSum*10 + i)%MOD; int nowLcm = preLcm; if(i) nowLcm = lcm(nowLcm, i); ans += dfs(pos-1, nowSum, nowLcm, flag && i == end); } if(!flag) dp[pos][preSum][index[preLcm]] = ans; return ans; } LL solve(LL n) { int len = 0; while(n) { bit[len++] = n%10; n /= 10; } return dfs(len-1,0,1,1); } int main() { int t; LL a, b; init(); scanf("%d",&t); while(t--) { scanf("%lld%lld", &a, &b); printf("%lld\n", solve(b) - solve(a-1) ); } return 0; }
数位DP(CodeForces 55D Beautiful numbers)
标签:
原文地址:http://www.cnblogs.com/chenchengxun/p/4453776.html