BZOJ3679 : 数字之积
设f[i][p2][p3][p5][p7][j][k]表示前i位,2,3,5,7的次数,前i位是否等于x,是否有数字的方案数
然后数位DP即可,ans=cal(r)-cal(l)
#include<cstdio> typedef long long ll; int n,a[20],len,i,j,m2,m3,m5,m7,t,p2,p3,p5,p7,c2[10],c3[10],c5[10],c7[10],pow2[30],pow3[20],pow5[14],pow7[12]; ll l,r,tmp,f[20][30][20][14][12][2][2]; ll cal(ll x){ for(len=0,tmp=x;tmp;a[++len]=tmp%10,tmp/=10); for(i=1,j=len;i<=len&&i<j;i++,j--)t=a[i],a[i]=a[j],a[j]=t; for(i=1;i<=len;i++)for(p2=0;p2<=m2;p2++)for(p3=0;p3<=m3;p3++)for(p5=0;p5<=m5;p5++)for(p7=0;p7<=m7;p7++)f[i][p2][p3][p5][p7][0][0]=f[i][p2][p3][p5][p7][0][1]=f[i][p2][p3][p5][p7][1][1]=0; for(i=0;i<=a[1];i++)f[1][c2[i]][c3[i]][c5[i]][c7[i]][i==a[1]][i>0]=1; for(i=1;i<len;i++)for(p2=0;p2<=m2;p2++)for(p3=0;p3<=m3;p3++)for(p5=0;p5<=m5;p5++)for(p7=0;p7<=m7;p7++)if(pow2[p2]*pow3[p3]*pow5[p5]*pow7[p7]<=n){ if(f[i][p2][p3][p5][p7][0][0])for(j=0;j<=9;j++)f[i+1][p2+c2[j]][p3+c3[j]][p5+c5[j]][p7+c7[j]][0][j>0]+=f[i][p2][p3][p5][p7][0][0]; if(f[i][p2][p3][p5][p7][0][1])for(j=1;j<=9;j++)f[i+1][p2+c2[j]][p3+c3[j]][p5+c5[j]][p7+c7[j]][0][1]+=f[i][p2][p3][p5][p7][0][1]; if(f[i][p2][p3][p5][p7][1][1])for(j=1;j<=a[i+1];j++)f[i+1][p2+c2[j]][p3+c3[j]][p5+c5[j]][p7+c7[j]][j==a[i+1]][1]+=f[i][p2][p3][p5][p7][1][1]; } for(p2=0;p2<=m2;p2++)for(p3=0;p3<=m3;p3++)for(p5=0;p5<=m5;p5++)for(p7=0;p7<=m7;p7++)if(pow2[p2]*pow3[p3]*pow5[p5]*pow7[p7]<=n)tmp+=f[len][p2][p3][p5][p7][0][1]; return tmp; } int main(){ c2[2]=1;c3[3]=1;c2[4]=2;c5[5]=1;c2[6]=1;c3[6]=1;c7[7]=1;c2[8]=3;c3[9]=2; scanf("%d%lld%lld",&n,&l,&r); for(t=n;t>1;t/=2,m2++); for(t=n;t>1;t/=3,m3++); for(t=n;t>1;t/=5,m5++); for(t=n;t>1;t/=7,m7++); for(i=pow2[0]=1;i<=m2;i++)pow2[i]=pow2[i-1]*2; for(i=pow3[0]=1;i<=m3;i++)pow3[i]=pow3[i-1]*3; for(i=pow5[0]=1;i<=m5;i++)pow5[i]=pow5[i-1]*5; for(i=pow7[0]=1;i<=m7;i++)pow7[i]=pow7[i-1]*7; printf("%lld",cal(r)-cal(l)); return 0; }