CF55D Beautiful numbers

一、題目

點此看題

二、解法

首先一個數滿足被一堆數整除等價於這個數滿足被這一堆數的最小公倍數整除,[1,9][1,9]的最小公倍數是25202520,且這個數有4848個因數。

定義dp[i][j][k][l]dp[i][j][k][l],爲ii位,是否頂到上界,模25202520的餘數爲kk,現在的最小公倍數爲ll(映射之後存進去,最多4848個),最後再判斷k%l=0k\%l=0是否成立,成立就產生11的貢獻。

好像代碼我換了一個寫法,去掉了第二維,只記錄未頂到上界的dpdp值,頂到上界的dpdp值就自己去dpdp,不記錄。

#include <cstdio>
#include <cstring>
#define int long long
const int M = 2525;
const int jzm = 2520;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int T,l,r,n,res,a[20],c[M],dp[20][M][50];
int gcd(int a,int b)
{
    return !b?a:gcd(b,a%b);
}
int lcm(int a,int b)
{
    if(!a || !b) return a|b;
    return a/gcd(a,b)*b;
}
int dfs(int x,int up,int y,int z)
{
    if(x==0) return y%z==0;
    if(!up && dp[x][y][c[z]]!=-1) return dp[x][y][c[z]];
    int t=0;
    for(int p=0;p<=9;p++)
    {
        if(up && p>a[x]) continue;
        t+=dfs(x-1,(up&&p==a[x]),(y*10+p)%jzm,lcm(z,p));
    }
    if(!up) dp[x][y][c[z]]=t;
    return t;
}
int cal(int x)
{
    n=res=0;
    while(x) a[++n]=x%10,x/=10;
    return dfs(n,1,0,1);
}
signed main()
{
    for(int i=1;i<=jzm;i++)
        if(jzm%i==0)
            c[i]=++n;
    T=read();
    memset(dp,-1,sizeof dp);
    while(T--)
    {
        l=read();r=read();
        printf("%lld\n",cal(r)-cal(l-1));
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章