【CodeForces 55D】Beautiful number 数位DP

Problem

https://vjudge.net/problem/CodeForces-55D

Solution

http://blog.csdn.net/lhq_er/article/details/77017024
代码更新过了,这个链接里的只能做到 1018 ,这个能到 91018

CODE

/*
 * @key words: digit DP
 * @tested on: CF 55D 1058ms
 * @Author: LuHaoqi 
 * @Date: 2017-08-11 17:22:47 
 * @Last Modified by: LuHaoqi
 * @Last Modified time: 2017-08-11 17:42:48
 */
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define ll long long
ll pow10[22],Pow[22],dp[22][2][2520][50];
int num[22],flcm[512],Map[2521],Map2[50],tmp[22],tot;

int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int lcm(int a,int b)
{
    if (a==0) return b;
    else if (b==0) return a;
    else return a/gcd(a,b)*b;
}
ll solve(ll x)
{
    int len=0;
    ll ans=0;
    while (x) tmp[++len]=x%10,x/=10;
    for (int i=1;i<=len;i++) num[i]=tmp[len-i+1];
    memset(dp,0,sizeof(dp));
    dp[0][1][0][0]=1;
    for (int i=0;i<=len;i++)
        for (int j=0;j<2;j++)
            for (int k=0;k<2520;k++)
                for (int l=0;l<tot;l++)
                {
                    ll p=dp[i][j][k][l];
                    int pp=Map2[l];
                    if (!p) continue;
                    if (i==len) 
                    {
                        if (k % pp==0) ans+=p;
                        continue;
                    }
                    if (j==0)
                    {
                        for (int q=0;q<=9;q++)
                            dp[i+1][0][(k+q*Pow[len-i-1])%2520][Map[lcm(pp,q)]]+=p;                     
                    }
                    else
                    {
                        for (int q=0;q<num[i+1];q++)
                            dp[i+1][0][(k+q*Pow[len-i-1])%2520][Map[lcm(pp,q)]]+=p;
                        dp[i+1][1][(k+num[i+1]*Pow[len-i-1])%2520][Map[lcm(pp,num[i+1])]]+=p;
                    }               
                }
    return ans;
}
void prepare()
{
    pow10[0]=Pow[0]=1;
    for (int i=1;i<=18;i++) pow10[i]=pow10[i-1]*10,Pow[i]=pow10[i]%2520;
    for (int i=1;i<(1<<9);i++)
        for (int j=1;j<=9;j++)
            if (i & (1<<j-1))
                flcm[i]=lcm(flcm[i-(1<<j-1)],j);
    for (int i=1;i<(1<<9);i++)
        if (!Map[flcm[i]]) Map[flcm[i]]=tot++,Map2[tot-1]=flcm[i];
}
int main()
{
    prepare();
    int T;
    scanf("%d",&T);
    while (T--)
    {
        ll a,b;
        cin>>a>>b;
        cout<<solve(b)-solve(a-1)<<endl;
    }   
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值