您的位置:首页 > 其它

[数位dp] cf 55D Beautiful numbers

2014-09-10 17:09 260 查看
题意:求[x,y]内,能被各个非零位整数的数的个数 比如312能被3、1、2整除所以算一个。

思路:首先最小公倍数的话1~9最大的是2520,然后只要顺着到当前位前的lcm是多少dfs下去就好了。

但是显然dp[20][2520][2520]是开不下的,但是注意到,到当前位的lcm是离散的,其实只有48个。

所以需要离散化成 dp[20][2520][50] 。

然后就是注意到当前位前的lcm了,处理会比较麻烦一点。

因为0的时候要跳过,第一位之前是没有的。

我的处理方式就是遇到之前的没有把之前的那位当前是本身这位。

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
#define eps 1e-8
using namespace std;
int gcd(int x,int y)
{
    return y?gcd(y,x%y):x;
}
int num[22],m,lcm[100],used[2700];  //used是数对应的编号,lcm是编号对应的数是多少
__int64 dp[22][2700][50],ten[22];
__int64 dfs(int site,int mod,int lcmid,int f)
{
    if(site==0)
    {
        if(lcmid==-1) return 0;
        return mod%lcm[lcmid]?0:1;
    }
    if(!f&&dp[site][mod][lcmid]!=-1) return dp[site][mod][lcmid];
    int len=f?num[site]:9;
    __int64 ans=0;
    for(int i=0; i<=len; i++)
    {
        int tep;
        if(lcmid!=-1) tep=lcm[lcmid];  //如果不是-1 就说明出现过了 直接赋值
        else
        {
            if(i==0)
            {
                ans+=dfs(site-1,(mod+i*ten[site])%2520,-1,f&&i==len);  //没有出现过又是0的话 跳过
                continue;   //记得continue
            }
            tep=i;  //不是0的话 就当做本身
            if(used[tep]==-1)
            {
                used[tep]=m;
                lcm[m++]=tep;
            }
        }
        tep=i?tep/gcd(tep,i)*i:tep;  //不是0的话计算,是0的话就是之前的
        if(used[tep]==-1)
        {
            used[tep]=m;
            lcm[m++]=tep;
        }
        tep=used[tep];
        ans+=dfs(site-1,(mod+i*ten[site])%2520,tep,f&&i==len);
    }
    if(!f&&lcmid!=-1) dp[site][mod][lcmid]=ans;
    return ans;
}
__int64 solve(__int64 x)
{
    if(x==0) return 0;
    int cnt=0;
    while(x)
    {
        num[++cnt]=x%10;
        x/=10;
    }
    return dfs(cnt,0,-1,1);
}
int main()
{
    int t;
    cin>>t;
    memset(dp,-1,sizeof(dp));
    m=0;
    memset(lcm,0,sizeof(lcm));
    memset(used,-1,sizeof(used));
    ten[1]=1;
    for(int i=2; i<=20; i++) ten[i]=(ten[i-1]*10)%2520;
    while(t--)
    {
        __int64 x,y;
        scanf("%I64d%I64d",&x,&y);
        printf("%I64d\n",solve(y)-solve(x-1));
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: