首页 > 代码库 > BZOJ 3679 数位DP

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 longint 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