• Codeforces 55D


    题目链接:https://cn.vjudge.net/problem/CodeForces-55D

    Volodya is an odd boy and his taste is strange as well. It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits. We will not argue with this and just count the quantity of beautiful numbers in given ranges.

    Input

    The first line of the input contains the number of cases t (1 ≤ t ≤ 10). Each of the next t lines contains two natural numbers li and ri (1 ≤ li ≤ ri ≤ 9 ·1018).

    Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered to use cin (also you may use %I64d).

    Output

    Output should contain t numbers — answers to the queries, one number per line — quantities of beautiful numbers in given intervals (from li to ri, inclusively).

    Example

    Input
    1
    1 9
    Output
    9
    Input
    1
    12 15
    Output
    2

    题解:

    首先,有 X % a = [ X % ( b * a ) ] % a,其中a,b,X均为正整数;

    证明:设X = m * a + n;(其中n<a)

       则 [ X % ( b * a ) ] % a

        = [ ( m * a + n ) % ( b * a ) ] % a

        = [ ( m * a ) % ( b * a ) + n %  ( b * a ) ] % a

        = [ a * ( m % b ) + n %  ( b * a ) ] % a

        = [ n %  ( b * a ) ] % a  (因为n<a,所以必然n<b*a,所以n %  ( b * a ) = n)

        = n % a  (因为n<a,所以n % a = n)

        = n = X % a

    当我们想判断一个数是否能被它的所有位上的非零数字整除时,可以判断这个数是否能被它的所有位上的非零数字的最小公倍数整除;

    也就是说,我们有一个数X,a = lcm( all non-zero digit(X) ),我们要判断X % a == 0?

    就可以先想出一个数字b * a,让X先对 b * a 取模,再对a取模判断,结果是一样的;

    那么哪个数字b * a是通用的呢?显然,lcm(1,2,3,…,9)就是最佳人选。

    经计算lcm(1,2,3,…,9) = 2520,

    也就是说,我们可以先在dfs过程中计算出某一个数X对2520的取模值mod,同时计算出某一个数X的所有数位上的数的最小公倍数lcm;

    最后我们只要判断mod % lcm == 0?即可判断X是否整除lcm。

    所以就不难设计出dfs(pos,mod,lcm,limit)函数;

    然后,我们发现dp[pos][mod][lcm],规模约有4*(19*2520*2520) = 4*120657600 B ≈ 471318.75 KB,题目并不允许开这么大的空间,所以需要离散化;

    不难发现,某一个数X的所有数位上的数的最小公倍数lcm,其必须是2520的因数,而我们通过如下代码:

    void discretize()
    {
        int cnt=0;
        for(int i=1;i<=MOD;i++)
            if(MOD % i == 0) ++cnt;
        cout<<cnt<<endl;
    }

    就能知道1~2520中只有48个数,是2520的因数。

    然后,我们只要把这48个数,离散化编号即可,这样dp数组lcm维度就可以从2520降到48,就不会超出题目规定的内存空间。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MOD = 2520;
    int dig[20];
    int idx[MOD+3];
    ll dp[20][2525][50];
    
    inline ll gcd(ll m,ll n){return n?gcd(n,m%n):m;}
    inline ll lcm(ll m,ll n){return m/gcd(m,n)*n;}
    void discretize()
    {
        int cnt=0;
        for(int i=1;i<=MOD;i++)
            if(MOD % i == 0)
            {
                idx[i]=++cnt;
                //cout<<"idx["<<i<<"]="<<idx[i]<<endl;
            }
        //cout<<cnt<<endl;
    }
    
    ll dfs(int pos,int mod,int Lcm,bool limit)
    {
        if(pos==0) return mod%Lcm==0;
        if(!limit && dp[pos][mod][idx[Lcm]]!=-1) return dp[pos][mod][idx[Lcm]];
    
        int up=limit?dig[pos]:9;
        ll ans=0;
        for(int i=0;i<=up;i++)
        {
            if(i==0) ans+=dfs(pos-1,(mod*10+i)%MOD,Lcm,limit && i==up);
            else ans+=dfs(pos-1,(mod*10+i)%MOD,lcm(Lcm,i),limit && i==up);
        }
    
        if(!limit) dp[pos][mod][idx[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 main()
    {
        discretize();
        int t;
        scanf("%d",&t);
        memset(dp,-1,sizeof(dp));
        while(t--)
        {
            ll l,r;
            scanf("%I64d%I64d",&l,&r);
            printf("%I64d
    ",solve(r)-solve(l-1));
        }
    }
  • 相关阅读:
    线段树时间分治
    CDQ分治
    并查集练习
    hihocoder 1513 小Hi的烦恼 (bitset优化)
    线段树维护哈希
    使用swift语言进行IOS应用开发
    用jquery+Asp.Net实现省市二级联动
    苹果IOS与谷歌 android系统的UI设计原则
    优秀设计师应当知道的20大UI设计原则
    JQuery Easy Ui dataGrid 数据表格
  • 原文地址:https://www.cnblogs.com/dilthey/p/8542011.html
Copyright © 2020-2023  润新知