BZOJ 3679 数字之积 - 数位dp
分析(From Claris):
考虑计算[1;R)内满足条件的数的个数。
数字之积非常大,但是这些数字的质因子只可能是2、3、5、7。
所以设f(i;cnt2;cnt3;cnt5;cnt7;j)为从高到低填了前i 位,2、3、5、7的个数分别为cnt2、cnt3、cnt5、cnt7,是否小于R的状态为j 的数字个数,然后DP即可。
#include<cstdio>
#include<cstring>
#define MAXTW 54
#define MAXTH 54
#define MAXFV 18
#define MAXSV 18
#define MAXST 1092025
typedef long long LL;
struct node{
int tw,th,fv,sv;
void Insert(int a,int b,int c,int d){
tw=a,th=b,fv=c,sv=d;
}
}st[2][MAXST+10][2];
int n,prime[20]={0,2,3,5,7},fac[20][10],cnt[2][2],lmt[20];
int id[2][MAXTW+1][MAXTH+1][MAXFV+1][MAXSV+1][2];
LL dp[2][MAXST+10][2];
int Getnum(LL x){
memset(lmt,0,sizeof lmt);
int ret=0,k=0;
for(LL y=x;y;y/=10)
ret++;
for(LL y=x;y;y/=10,k++)
lmt[ret-k]=y%10;
return ret;
}
void Insert(int f,int tw,int th,int fv,int sv,int cmp,LL val)
{
if(id[f][tw][th][fv][sv][cmp]==-1){
id[f][tw][th][fv][sv][cmp]=++cnt[f][cmp];
st[f][cnt[f][cmp]][cmp].Insert(tw,th,fv,sv);
dp[f][cnt[f][cmp]][cmp]=val;
}
else
dp[f][id[f][tw][th][fv][sv][cmp]][cmp]+=val;
}
bool check(node x,int a1,int a2,int a3,int a4)
{
LL k=1;
for(int i=x.tw+a1;i>=1;i--)
k*=2;
for(int i=x.th+a2;i>=1;i--)
k*=3;
for(int i=x.fv+a3;i>=1;i--)
k*=5;
for(int i=x.sv+a4;i>=1;i--)
k*=7;
if(k>0&&k<=n) return true;
else return false;
}
void Getclear(int f)
{
cnt[f][0]=cnt[f][1]=0;
memset(dp[f],0,sizeof dp[f]);
memset(st[f],0,sizeof st[f]);
memset(id[f],-1,sizeof id[f]);
}
LL DP(LL num)
{
if(!num) return 0;
int m=Getnum(num),f=0;
Getclear(f);
for(int i=1;i<lmt[1];i++)
Insert(f,fac[i][1],fac[i][2],fac[i][3],fac[i][4],0,1);
Insert(f,fac[lmt[1]][1],fac[lmt[1]][2],fac[lmt[1]][3],fac[lmt[1]][4],1,1);
for(int i=2;i<=m;i++){
Getclear(f^1);
Insert(f,0,0,0,0,0,1);
for(int j=1;j<=cnt[f][0];j++){
for(int k=1;k<=9;k++){
if(!check(st[f][j][0],fac[k][1],fac[k][2],fac[k][3],fac[k][4]))
continue;
Insert(f^1,st[f][j][0].tw+fac[k][1],st[f][j][0].th+fac[k][2],st[f][j][0].fv+fac[k][3],st[f][j][0].sv+fac[k][4],0,dp[f][j][0]);
}
}
for(int j=1;j<=cnt[f][1];j++){
for(int k=1;k<lmt[i];k++){
if(!check(st[f][j][1],fac[k][1],fac[k][2],fac[k][3],fac[k][4]))
continue;
Insert(f^1,st[f][j][1].tw+fac[k][1],st[f][j][1].th+fac[k][2],st[f][j][1].fv+fac[k][3],st[f][j][1].sv+fac[k][4],0,dp[f][j][1]);
}
if(lmt[i]==0) continue;
if(!check(st[f][j][1],fac[lmt[i]][1],fac[lmt[i]][2],fac[lmt[i]][3],fac[lmt[i]][4]))
continue;
Insert(f^1,st[f][j][1].tw+fac[lmt[i]][1],st[f][j][1].th+fac[lmt[i]][2],st[f][j][1].fv+fac[lmt[i]][3],st[f][j][1].sv+fac[lmt[i]][4],1,dp[f][j][1]);
}
f^=1;
}
LL ret=0;
for(int d=0;d<2;d++)
for(int j=1;j<=cnt[f][d];j++)
ret+=dp[f][j][d];
return ret;
}
void prepare()
{
for(int i=1;i<=9;i++){
for(int j=1,x=i;j<=4;j++){
if(x%prime[j]) continue;
fac[i][0]++;
while(x%prime[j]==0){
x/=prime[j];
fac[i][j]++;
}
}
}
}
int main()
{
LL L,R;
prepare();
scanf("%d%lld%lld",&n,&L,&R);
printf("%lld\n",DP(R-1)-DP(L-1));
return 0;
}