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));
}

 

posted @ 2017-04-01 08:34  SiriusRen  阅读(223)  评论(0编辑  收藏  举报