1. 程式人生 > >Beautiful numbers-取模數位DP

Beautiful numbers-取模數位DP

  • 題意:It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits
  • 在他看來,正整數是優美的,當且僅當它是由它的每個非零數字整除時。
  • zyl思路:數位DP時我們只需儲存前面那些位的最小公倍數就可進行狀態轉移,到邊界時就把所有位的lcm求出了,為了判斷這個數能否被它的所有數位整除,我們還需要這個數的值,顯然要記錄值是不可能的,其實我們只需記錄它對2520的模即可,這樣我們就可以設計出如下數位DP:dfs(pos,mod,lcm,f),pos為當前位,mod為前面那些位對2520的模,lcm為前面那些數位的最小公倍數,f標記前面那些位是否達到上限,這樣一來dp陣列就要開到19*2520*2520,明顯超記憶體了,考慮到最小公倍數是離散的,1-2520中可能是最小公倍數的其實只有48個,經過離散化處理後,dp陣列的最後一維可以降到48,這樣就不會超了
  • #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    long long dp[40][2530][50];
    int ls[3000],cnt=0;
    int f[30],k;
    
    int gcd(int a,int b)
    {
        return a==0 ? b:gcd(b%a,a);
    }
    
    long long dfs(int pos,int mod,int lcm,bool flag)
    {
        if(pos==0)return mod%lcm==0;
        if(!flag&&dp[pos][mod][ls[lcm]]!=-1)return dp[pos][mod][ls[lcm]];
        int maxx=9;
        if(flag)maxx=f[pos];
        long long ans=0;
        for(int i=0; i<=maxx; i++)
        {
            int modd=(mod*10+i)%2520;
            int lcmm=lcm;
            if(i!=0)
            {
                lcmm=lcm/(gcd(lcm,i))*i;
            }
            ans+=dfs(pos-1,modd,lcmm,flag&&i==maxx);
        }
        if(!flag)dp[pos][mod][ls[lcm]]=ans;
        return ans;
    }
    long long solve(long long x)
    {
        k=0;
        while(x)
        {
            f[++k]=x%10;
            x=x/10;
        }
        return dfs(k,0,1,1);
    }
    
    int main()
    {
        for(int i=1; i<=2520; i++)
        {
            if(2520%i==0)
            {
                ls[i]=++cnt;
            }
        }
        memset(dp,-1,sizeof(dp));
        int t;
        cin>>t;
        while(t--)
        {
            long long a,b;
            cin>>a>>b;
            long long ans=solve(b)-solve(a-1);
            cout<<ans<<endl;
        }
        return 0;
    }