bzoj 3679 数字之积

比较裸(shen)的数位dp。可以预处理出来所有可以到达的乘积,然后dp。
我会说我重变量名wa了好久吗?
我会说我dp没错,预处理错了又wa了好久吗?
因为重变量,代码很不优美。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#define md
#define ll long long
//#define inf (int) 1e9
#define eps 1e-8
#define N
#define Q 101000
#define K 10010
using namespace std;
ll q[Q];
ll f[20][2][K];
int mxn,a[20],tot;
map<int,int> mp;
ll cal(int a,int b,int c,int d)
{
long long ans=1;
for (int i=1;i<=a;i++) ans*=2;
if (ans>mxn) return 0;
for (int j=1;j<=b;j++) ans*=3;
if (ans>mxn) return 0;
for (int k=1;k<=c;k++) ans*=5;
if (ans>mxn) return 0;
for (int l=1;l<=d;l++) ans*=7;
if (ans>mxn) return 0;
return ans;
}
void ycl()
{
for (int a=0;a<=31;a++)
for (int b=0;b<=18;b++)
for (int c=0;c<=13;c++)
for (int d=0;d<=10;d++)
{
ll x=cal(a,b,c,d);
if (x) { q[++tot]=x; mp[x]=tot;}
}
}
ll dp(ll x)
{
if (x==0) return 0;
memset(f,0,sizeof(f));
int len=0;
while (x)
{
a[++len]=x%10;
x/=10;
}
reverse(a+1,a+len+1);
for (int i=1;i<=a[1]&&i<=mxn;i++) f[1][i==a[1]][mp[i]]++;
for (int i=1;i<=len-1;i++)
{
for (int j=1;j<=tot;j++)
{
if (f[i][0][j])
{
ll x=q[j];
ll *p=f[i+1][0],*q=f[i][0];
for (int k=0;k<=9&&k*x<=mxn;k++)
p[mp[k*x]]+=q[j];
}
if (f[i][1][j])
{
for (int k=0;k<=a[i+1]&&k*q[j]<=mxn;k++)
f[i+1][k==a[i+1]][mp[k*q[j]]]+=f[i][1][j];
}
}
}
ll ans=0;
ll *p=f[len][0],*qq=f[len][1];
for (int k=1;k<=tot;k++)
ans+=p[k]+qq[k];
memset(f,0,sizeof(f));
for (int i=1;i<=9&&i<=mxn;i++) f[1][0][mp[i]]++;
for (int i=1;i<=len-2;i++)
{
for (int j=1;j<=tot;j++)
if (f[i][0][j])
{
ll x=q[j];
ll *p=f[i+1][0],*q=f[i][0];
for (int k=0;k<=9&&k*x<=mxn;k++)
p[mp[k*x]]+=q[j];
}
}
for (int i=1;i<=len-1;i++)
{
ll *p=f[i][0];
for (int j=1;j<=tot;j++)
ans+=p[j];
}
return ans;
}

int main()
{
ll L,R,ans1,ans2;
scanf("%d%lld%lld",&mxn,&L,&R);
ycl();
ans1=dp(L-1); ans2=dp(R-1);
printf("%lld\n",ans2-ans1);
return 0;
}

你可能感兴趣的:(bzoj 3679 数字之积)