• FZU2179/Codeforces 55D beautiful number 数位DP


    题目大意:

    求  1(m)到n直接有多少个数字x满足 x可以整出这个数字的每一位上的数字

    思路:

    整除每一位。只需要整除每一位的lcm即可

    但是数字太大,dp状态怎么表示呢

    发现 1~9的LCM 是2520 ....也就是说只要对这个数mod2520 剩下的余数能整除lcm就可以整除了。。

    计数的时候还有一个技巧,具体见注释

    此外这个题还卡常数了,预处理lcm才过了。。

    代码如下:

    #include <iostream>
    #include <stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<string>
    #include<ctype.h>
    using namespace std;
    #define LCM 2520
    long long dp[20][LCM+10][50][2];
    long long n;
    int m;
    int state[50],hs[2530],s;
    bool vi[2530];
    int d[20];
    int Lcm[50][20];
    int gcd(int a,int b)
    {
        return b?gcd(b,a%b):a;
    }
    int lcm(int a,int b)
    {
        if(b==0)
            return a;
        return a/gcd(a,b)*b;
    }
    
    void ini()
    {
        m=0;
        while(n)
        {
            d[++m]=n%10;
            n/=10;
        }
        reverse(d+1,d+m+1);
    }
    void DP()
    {
        memset(dp,0,sizeof(dp));
        //先放最高位
        for(int i=1;i<d[1];i++)
        {
            dp[1][i][hs[i]][0]=1;        //dp...[0]存储的是前i位的数小于所求数的方案
        }
        dp[1][d[1]][hs[d[1]]][1]=1;      //dp...[1]存储的是前i位的数等于所求数的方案
        //从高位往下转移
        for(int i=2;i<=m;++i)
        {
            for(int j=1;j<10;++j)
                dp[i][j][hs[j]][0]=1;  //从大于1的数位开始放1~9都肯定小于所求数
            for(int j=0;j<2520;++j)
            {
                for(int k=0;k<s;++k)
                {
                    if(dp[i-1][j][k][0]==0&&dp[i-1][j][k][1]==0)
                        continue;
                    for(int t=0;t<=9;++t)
                    {
                        int sum=(j*10+t)%LCM;
                        int L=Lcm[k][t];
                        dp[i][sum][hs[L]][0]+=dp[i-1][j][k][0];
                        
                        //在当前位放的数小于等于所求数的当前为数的情况可以继承高位都等于所求数的方案
                        //否则,只能继承高位小于所求数的方案
                        if(t<d[i])    //当前位放的数小于所求数的当前位
                        {
                            dp[i][sum][hs[L]][0]+=dp[i-1][j][k][1];
                        }
                        if(t==d[i])   //当前位放的数等于所求数的当前位
                        {
                            dp[i][sum][hs[L]][1]+=dp[i-1][j][k][1];
                        }
                        
                    }
                }
            }
        }
    }
    void setstate()
    {
        memset(vi,0,sizeof(vi));
        s=0;
        int tmp;
        for(int i=0;i<(1<<9);i++)
        {
            tmp=1;
            for(int j=0;j<9;j++)
            {
                if((1<<j)&i)
                {
                    tmp=lcm(j+1,tmp);
                }
            }
            if(vi[tmp]==0)
            {
                state[s]=tmp;
                hs[tmp]=s++;
                vi[tmp]=1;
            }
        }
        for(int i=0;i<s;i++)
        {
            for(int j=0;j<=9;j++)
               Lcm[i][j]=lcm(state[i],j);
        }
    }
    long long cal()
    {
        long long ans=0;
    
        for(int i=0;i<2520;i++)
        {
            for(int j=0;j<s;j++)
            {
                if(i%state[j]==0)
                    ans+=dp[m][i][j][0]+dp[m][i][j][1];
            }
        }
        return ans;
    }
    long long solve(long long x)
    {
        n=x;
        ini();
        DP();
        return cal();
    }
    int main()
    {
        long long a,b;
        setstate();
        int t;
        scanf("%d",&t);
        while(t--)
        {
            //scanf("%I64d%I64d",&a,&b);
            scanf("%I64d",&a);
            //cout<<solve(b)-solve(a-1)<<endl;
            cout<<solve(a)<<endl;
        }
        return 0;
    }
  • 相关阅读:
    POJ3259
    常见OJ评判结果对照表
    python初尝试,写一个简单的爬虫程序
    springboot整合swagger,前后端接口规范
    idea 简单添加springmvc
    idea 搭建web项目
    java实现二分查找
    python语法
    kafka linux 常用操作指令
    spring 容器
  • 原文地址:https://www.cnblogs.com/oneshot/p/4110210.html
Copyright © 2020-2023  润新知