数位dp CodeForces - 55D 美丽数字

匿名 (未验证) 提交于 2019-12-02 23:55:01

题意:定义能被自己所有位数整除的数字为美丽,给定一个区间,求区间内的美丽数字个数。

分析:首先,可以把限制条件转化为之前所有位数的最大公倍数dp[ pos ][ sum ][ lca ][ up ] 就代表着 pos 之后的位置全部遍历完后,该 状态取这个sum的最大值。这里要避免一个问题,就是 15 和 12,不可以从 15 的 dp[ pos=1 ][ sum=0 ][ up=1 ] 的记忆直接得到 12 的 dp[ pos=1 ][ sum=0 ][ up=1 ] ,而数位dp又需要这样的记忆化来减少时间复杂度,因此,这里的 up 就有了两个作用,即判断某个位置可以遍历到数字几 和 将15 的dp[ 1 ] 定义为饱和

然后发现MLE了,原因在于数组开太大 ,而1~9的公倍数为2520,[ sum ]的最大值就可以看成 2520,大的就用取模(有相关数论),所以这个只要开2520。并且,[ lca ]位置很多都没用上,1~9的公倍数就那么多少个,所以就要用到离散化,建立一个Hash数组,在操作dp这个数组的时候,把[ lca ]位置的值用Hash数组转化为 cnt 就行了,这个数字大概就50个。

还可以看到Lcm(a,b)=a/gcd(a,b)*b

#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std;  typedef long long ll; const int maxn=32; const int Mod=2520; ll n,m; int dig[maxn]; ll dp[maxn][2550][50][2]; int Hash[2550];  int gcd(int a,int b){     if(b==0) return a;     return gcd(b,a%b); } int Lcm(int a,int b){     return a/gcd(a,b)*b; }  ll dfs(int pos,int sum,int lcm,bool up) {     // printf("state = %d %d %d %d \n", pos,sum,lcm,up);     if(pos<0) return sum%lcm==0;     if(!up&&dp[pos][sum][Hash[lcm]][up]!=-1) {         printf("dp %d %d %d %d = %d\n", pos,sum,lcm,up,dp[pos][sum][Hash[lcm]][up]);         return dp[pos][sum][Hash[lcm]][up];     }     ll res=0;     for(int i=0; i<=9; i++){         if(up==1 && i>dig[pos]) break;         int tlcm=lcm;         if(i) tlcm=Lcm(tlcm,i);         res += dfs(pos-1,(sum*10+i)%Mod,tlcm,up&&i==dig[pos]);         // printf("res=%lld\n",res );     }     if(!up) dp[pos][sum][Hash[lcm]][up]=res;     return res; }  ll sol(ll x){     if(x<0) return 0;     // memset(dp,-1,sizeof(dp));     int cnt=0;     while(x){         dig[cnt++]=x%10;         x/=10;     }     return dfs(cnt-1,0,1,1); }  int main(){     int T;     cin>>T;     int cnt=0;     for(int i=1; i<=Mod; i++){         if(Mod%i==0){             Hash[i]=cnt++;         }     }     // printf("Hash=%d\n", Hash[126]);     memset(dp,-1,sizeof(dp));     while(T--){         cin>>n>>m;         cout<<sol(m)-sol(n-1)<<endl;     } }

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!