51nod 1232 完美数 | 数位DP

51nod 1232 完美数

题面

如果一个十进制数的每一位都是它的因数,则称这个数为完美数。
给出L, R(L, R <= 1e18),求出[L, R]中完美数的个数。

题解

做这道题,我才了解数位DP的套路写法……下次做数位DP应该就不会绞尽脑汁处理写法上的问题了。

dp[i][j][k]表示长度为i,模2560(1~9的LCM)得j,所有位上的数的LCM为k的数的个数。
它包括了所有的长度为i的数,例如i=5时,它要考虑的是10000~99999之间所有的数。

这里的k理论上也是一个小于等于2560的数,但这样太大了,需要离散化一下。打表发现1~9不同组合的LCM只有48个,很适合离散化。

数位DP的套路:用一个记忆化的dfs解决问题。详见代码。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define INF 0x3f3f3f3f
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;
typedef long long ll;
template <class T>
bool read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
	if(c == '-') op = 1;
	else if(c == EOF) return 0;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
	x = x * 10 + c - '0';
    if(op) x = -x;
    return 1;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
const int N = 2530, M = 50;
int gcd(int a, int b){ return b ? gcd(b, a % b) : a; }
int lcm(int a, int b){ return a / gcd(a, b) * b; }
int f[N], g[]={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};
ll T, L, R, num[20];
ll dp[20][N][M];
void init(){
    for(int i = 1; i <= 48; i++)
	f[g[i]] = i;
    memset(dp, -1, sizeof(dp));
}
ll dfs(int i, int j, int k, bool flag){
    if(!i) return j % g[k] == 0;
    if(!flag && dp[i][j][k] != -1) return dp[i][j][k];
    ll res = 0, lim = flag ? num[i] : 9;
    for(int x = 0; x <= lim; x++){
	int newk = x ? f[lcm(g[k], x)] : k;
	res += dfs(i - 1, (j * 10 + x) % 2520, newk, flag && x == lim);
    }
    return flag ? res : dp[i][j][k] = res;
}
ll solve(ll x){
    int len = 0;
    while(x) num[++len] = x % 10, x /= 10;
    return dfs(len, 0, 1, 1);
}
int main(){
    init();
    read(T);
    while(T--){
	read(L), read(R);
	write(solve(R) - solve(L - 1)), enter;
    }
    return 0;
}
posted @ 2017-11-02 17:17  胡小兔  阅读(568)  评论(1编辑  收藏  举报