CodeForces 55D Beautiful numbers (数位DP)

来源:互联网 发布:微信公众号淘宝客制作 编辑:程序博客网 时间:2024/06/14 00:02

          想了半天,总算想出来了。这题刚上来的思路很明显是11维DP。。但是明显不可取。。

         这题的关键在于只要两个数前面的拥有的数字是一样的,而且此时与其最小公倍数的模是一样的,那么这时候就可以认为对所有的数字取模都是相等的,那么后面的总情况数属于完美数的情况也是相同的。

         只要想到这步的话,那么基本思路就出来了,我第一次居然脑残的记录lcm与模2520(2到9的最小公倍数),首先lcm相同并不代表出现的数字相同先不说,仅仅这个最大值就太大了,lcm最大是2520,这样的话就需要开一个20*2520*2520的数组,我一看给的内存挺大的,就这么写了,然后提交。。果然MLE  on TEST 1.。。。

         然后才用的二进制状压记录2到9出现的数,因为0到1不用记录,所以只需要开1<<8大小就可以了。

这样空间复杂度就少了很多。然后就这样一改,果然AC了。

代码如下:

#include <iostream>#include <string.h>#include <math.h>#include <queue>#include <algorithm>#include <stdlib.h>#include <map>#include <set>#include <stdio.h>using namespace std;#define LL __int64#define pi acos(-1.0)const int mod=2520;const int INF=0x3f3f3f3f;const double eqs=1e-8;LL dp[19][257][2530], c[20], lcm[257];int gcd(int x, int y){    return y==0?x:gcd(y,x%y);}int getlcm(int x, int y){    if(!x) return y;    return x*y/gcd(x,y);}int find1(int x, int y){    if(y<=1) return x;    y-=2;    if(x&(1<<y)) return x;    return x|(1<<y);}int init(){    int ans=1;    int i, j;    lcm[0]=1;    for(i=1;i<=255;i++){        ans=1;        for(j=2;j<=9;j++){            if(i&(1<<(j-2))){                ans=getlcm(ans,j);            }        }        lcm[i]=ans;    }}LL dfs(int cnt, int maxd, int zero, int z, int mods){    if(cnt==-1) return !(mods%lcm[z]);    if(zero&&maxd&&dp[cnt][z][mods]!=-1) return dp[cnt][z][mods];    int i, r=maxd?9:c[cnt];    LL ans=0;    for(i=0;i<=r;i++){            ans+=dfs(cnt-1,maxd||i<r,zero||i,find1(z,i),(mods*10+i)%mod);        }    if(zero&&maxd) dp[cnt][z][mods]=ans;    return ans;}LL Cal(LL x){    int i, cnt=0;    while(x){        c[cnt++]=x%10;        x/=10;    }    return dfs(cnt-1,0,0,0,0);}int main(){    int t;    LL l, r;    memset(dp,-1,sizeof(dp));    init();    scanf("%d",&t);    while(t--){        scanf("%I64d%I64d",&l,&r);        printf("%I64d\n",Cal(r)-Cal(l-1));    }    return 0;}


1 0