BZOJ 3679 数位DP,离散化

来源:互联网 发布:linux设置默认启动项 编辑:程序博客网 时间:2024/06/01 09:36

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3679


解法: 比较裸的数位DP,dp[i][j][k]表示前i位,当前位数字为j,乘积为k(k保存的是离散化之后的值),然后按照数位DP的做法去写就可以了。


///BZOJ 3679///数位DP,离散化#include <bits/stdc++.h>using namespace std;typedef long long LL;LL dp[20][10][6000];///dp[i][j][k]前i位,当前位数字为j,乘积为k(k保存的是离散化之后的值)LL l, r;int digit[20];int a[6000];int n, tot, num;map<LL,int>p;///2,3,5,7bool check(int a, int b, int c, int d){    long long ans=1;    for(int i=1; i<=a; i++) ans*=2;    if(ans>n) return 0;    for(int i=1; i<=b; i++) ans*=3;    if(ans>n) return 0;    for(int i=1; i<=c; i++) ans*=5;    if(ans>n) return 0;    for(int i=1; i<=d; i++) ans*=7;    if(ans>n) return 0;    return 1;}int cal(int a, int b, int c, int d){    int ans=1;    for(int i=1; i<=a; i++) ans*=2;    for(int i=1; i<=b; i++) ans*=3;    for(int i=1; i<=c; i++) ans*=5;    for(int i=1; i<=d; i++) ans*=7;    return ans;}long long f(LL x){    LL ans=0;    num=0;    while(x){        digit[++num]=x%10;        x/=10;    }    for(int i=1; i<=num/2; i++) swap(digit[i],digit[num-i+1]);    for(int i=1; i<num; i++)        for(int j=1; j<=9; j++)            for(int k=1; k<=tot; k++)                ans += dp[num-i][j][k];    LL sum=1;    for(int i=1; i<=num; i++){        for(int j=1; j<digit[i]; j++){            for(int k=1; k<=tot; k++){                if(a[k]*sum>n) break;                ans+=dp[num-i+1][j][k];            }        }        sum*=digit[i];        if(sum>n||sum==0) break;    }    return ans;}int main(){    scanf("%d", &n);    for(int i=0; i<=31; i++){        for(int j=0; j<=18; j++){            for(int k=0; k<=13; k++){                for(int l=0; l<=10; l++){                    if(check(i,j,k,l)){                        a[++tot]=cal(i,j,k,l);                    }                }            }        }    }    sort(a+1,a+tot+1);    for(int i=1; i<=tot; i++) p[a[i]]=i;    scanf("%lld%lld",&l,&r);    for(int i=1; i<=9; i++) if(p[i]) dp[1][i][p[i]]=1;    for(int i=1; i<=18; i++){        for(int j=1; j<=9; j++){            for(int q=1; q<=tot; q++){                if(dp[i][j][q]){                    for(int k=1; k<=9; k++){                        if((long long)a[q]*k<=n && p[a[q]*k]) dp[i+1][k][p[a[q]*k]]+=dp[i][j][q];                    }                }            }        }    }    long long ans = f(r)-f(l);    printf("%lld\n", ans);    return 0;}


DFS版本:

#include <bits/stdc++.h>using namespace std;typedef long long LL;LL dp[20][6000];LL n;int cnt,a[20];map<LL,int> use;LL dfs(int pos,LL chengji,bool lead,bool limit){    if(chengji>n)        return 0;    if(use[chengji]==0)    {        use[chengji]=cnt++;    }    if(pos==-1)    {        if(chengji>0&&chengji<=n)            return 1;        return 0;    }    if(lead==1&&!limit&&dp[pos][use[chengji]]!=-1)        return dp[pos][use[chengji]];    int up=limit ? a[pos]:9;    LL ret=0;    for(int i=0;i<=up;i++)    {        if(i==0)        {            if(lead==true)                ret+=dfs(pos-1,chengji*i,true,limit&&i==a[pos]);            else                ret+=dfs(pos-1,0,false,limit&&i==a[pos]);        }        else        {             if(lead==true)                ret+=dfs(pos-1,chengji*i,true,limit&&i==a[pos]);             else                ret+=dfs(pos-1,i,true,limit&&i==a[pos]);        }    }    if(!limit&&lead)        dp[pos][use[chengji]]=ret;    return ret;}LL solve(LL x){    int pos=0;    while(x)    {        a[pos++]=x%10;        x/=10;    }    return dfs(pos-1,0,false,true);}int main(){    memset(dp,-1,sizeof(dp));    LL l,r;    use.clear();    cnt=1;    scanf("%lld",&n);    scanf("%lld%lld",&l,&r);    LL ans=solve(r-1)-solve(l-1);    printf("%lld\n",ans);return 0;}



0 0
原创粉丝点击