BZOJ 3679 数位DP

Posted SiriusRen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3679 数位DP相关的知识,希望对你有一定的参考价值。

思路:

f[i][j]表示i位数乘积为j的方案数

 j的取值最多5000多种,那就开个map存一下好了

f[i][mp[k*rec[j]]]+=f[i-1][j];
//By SiriusRen
#include <map> 
#include <cstdio>
using namespace std;
#define int long long
int n,L,R,tot,rec[6666],f[20][6666];
map<int,int>mp;
void dfs(int x){
    if(x>n||mp.find(x)!=mp.end())return;
    mp[x]=++tot,rec[tot]=x;
    for(int i=2;i<=9;i++)dfs(x*i);
}
map<int,int>::iterator it;
int calc(int m){
    int p=1,base=0,now=1,ans=0;
    for(;10*p<=m;base++,p*=10);
    for(int i=1;i<=base;i++)
        for(int j=1;j<=tot;j++)
            ans+=f[i][j];
    for(int i=base;i>=0;i--){
        for(int j=1;j<=tot;j++)
            for(int k=1;k<m/p;k++)
                if(rec[j]*k*now<=n)
                    ans+=f[i][j];
        now=m/p*now,m%=p,p/=10;
        if(!now)return ans;
    }
    return ans+(now<=n);
}
signed main(){
    scanf("%lld%lld%lld",&n,&L,&R);
    dfs(1),f[0][1]=1;
    for(int i=1;i<=18;i++)
        for(int j=1;j<=tot;j++)
            for(int k=1;k<=9;k++)
                if(k*rec[j]<=n)f[i][mp[k*rec[j]]]+=f[i-1][j];
    printf("%lld\n",calc(R-1)-calc(L-1));
}

 

以上是关于BZOJ 3679 数位DP的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3679 数字之积

5.30杂题选讲

数位DP 2

BZOJ1833: [ZJOI2010]count 数字计数 (数位dp)

BZOJ1026 [SCOI2009]windy数 数位dp

BZOJ1026: [SCOI2009]windy数 ( 数位dp )