FZU2179(数位dp)

传送门:Chriswho

题意:求区间[1,n]内能整除自己本身各位数字的数的个数。

分析:这题跟CF 55D Beautiful numbers一样的,一个数能被它的所有非零数位整除,则能被它们的最小公倍数整除,而1到9的最小公倍数为2520,为了判断这个数能否被它的所有数位整除,我们还需要这个数的值,但这里我们只需记录它对2520的模即可,dp[pos][sum][lcm]表示非限制条件下(limit==0),当前在第pos位模2520余sum且前面各位数字的最小公倍数为lcm的符合条件的数的总数。

 

#include <cstdio>

#include <cstring>

#include <string>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <queue>

#include <cstdlib>

#include <stack>

#include <vector>

#include <set>

#include <map>

#define LL long long

#define mod 100000000

#define inf 0x3f3f3f3f

#define eps 1e-6

#define N 1010

#define FILL(a,b) (memset(a,b,sizeof(a)))

#define lson l,m,rt<<1

#define rson m+1,r,rt<<1|1

#define PII pair<int,int>

using namespace std;

LL dp[20][2525][50];

int dig[20],num[2525];

LL times=0;

int gcd(int a,int b)

{

    return a%b==0?b:gcd(b,a%b);

}

LL dfs(int pos,int sum,int lcm,int limit)

{

    if(!pos){//times++;

            return sum%lcm==0;}

    if(!limit&&~dp[pos][sum][num[lcm]])return dp[pos][sum][num[lcm]];

    int len=limit?dig[pos]:9;

    LL ans=0;

    for(int i=0;i<=len;i++)

    {

        int newlcm;

        if(i==0)newlcm=lcm;

        else newlcm=lcm/gcd(i,lcm)*i;

        ans+=dfs(pos-1,(sum*10+i)%2520,newlcm,limit&&len==i);

    }

    if(!limit)dp[pos][sum][num[lcm]]=ans;

    return ans;

}

LL solve(LL x)

{

    int len=0;

    while(x)

    {

        dig[++len]=x%10;

        x/=10;

    }

    return dfs(len,0,1,1);

}

int check(LL n)

{

    LL x=n,flag=1;

    while(x)

    {

        int s=x%10;

        x/=10;

        if(s==0)continue;

        if(n%s)flag=0;

    }

    return flag;

}

LL fact(LL x)

{

    LL res=0;

    for(int i=1;i<=x;i++)

    {

        if(check(i))res++;

    }

    return res;

}

void init()

{

    FILL(dp,-1);

    int cnt=0;

    for(int i=1;i<=2520;i++)

        if(2520%i==0)num[i]=++cnt;

}

int main()

{

    LL n;

    int T;

    init();

    scanf("%d",&T);

    while(T--)

    {

        scanf("%I64d",&n);

        printf("%I64d\n",solve(n)-1);

      //  printf("%I64d\n",fact(b)-fact(a-1));

       // printf("%I64d\n",times);

    }

}
View Code

 

你可能感兴趣的:(dp)