【CF55D】Beautiful Numbers-数位DP+优化
测试地址:Beautiful Numbers
题目大意: 求在区间中,有多少能整除自身所有非零数位的数。
做法: 本题需要用到数位DP+优化。
首先这题一看就是数位DP,本题的关键是状态的设计以及优化。
我们很快能写出一个状态定义:表示前位,所有非零位的LCM是,对的余数是,不卡/卡上界的数的数目。但我们发现这个东西不能转移,当增加的时候,新的余数会有很多种情况,因此我们不能考虑这种状态定义。
我们发现,涉及到的所有的都是的因数,所以我们只需要的表示改成对的余数,那么是的整数倍时,就表示这些数满足题目中的条件。
这样我们就能转移了。但分析一下发现,时间复杂度是(位数)(求LCM)(枚举转移的位)(数据组数),T到没边,因此我们还要进一步进行优化。
打表或手算发现,不同的的数目,也就是的因数,只有个,因此用一个数组映射一下这些数,用映射后的值表示即可,优化掉一个。进而我们发现我们可以预处理出这些数之间的LCM,所以又优化掉了一个。进行这两个优化后,已经非常接近时限了,但还是会T掉。进一步观察发现,卡上界的情况中只有一个数,这个数的是确定的,不用跟随上面的枚举,因此我们根本不用存一维,只要维护当前上界的即可完成应完成的转移。所以又优化掉了一个,就可以通过此题了,最大点的时间为左右。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int LCM=2520;
int T,n,s[20],lcmlist[1050],id[3010],L[50][10],tot;
ll f[21][LCM+10][50];
int gcd(int a,int b)
{
return (b==0)?a:gcd(b,a%b);
}
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}
ll solve()
{
memset(f[n+1],0,sizeof(f[n+1]));
int toplcm=1,toprem=0;
for(int i=n;i>=1;i--)
{
memset(f[i],0,sizeof(f[i]));
for(int j=0;j<LCM;j++)
for(int k=1;k<=tot;k++)
for(int now=0;now<=9;now++)
f[i][(j*10+now)%LCM][L[k][now]]+=f[i+1][j][k];
if (i<n)
{
for(int now=0;now<s[i];now++)
f[i][(toprem*10+now)%LCM][L[toplcm][now]]++;
}
for(int j=1;j<=((i==n)?(s[i]-1):9);j++)
f[i][j][id[j]]++;
toplcm=L[toplcm][s[i]];
toprem=(toprem*10+s[i])%LCM;
}
ll ans=0;
for(int i=1;i<=tot;i++)
for(int j=0;j*lcmlist[i]<LCM;j++)
ans+=f[1][j*lcmlist[i]][i];
if (toprem%lcmlist[toplcm]==0) ans++;
return ans;
}
int main()
{
scanf("%d",&T);
tot=0;
for(int i=1;i<(1<<9);i++)
{
int x=1;
for(int j=1;j<=9;j++)
if ((1<<(j-1))&i) x=lcm(x,j);
lcmlist[++tot]=x;
}
sort(lcmlist+1,lcmlist+tot+1);
tot=0;
for(int i=1;i<(1<<9);i++)
if (i==1||lcmlist[i]!=lcmlist[tot])
{
lcmlist[++tot]=lcmlist[i];
id[lcmlist[tot]]=tot;
}
for(int i=1;i<=tot;i++)
for(int j=0;j<=9;j++)
L[i][j]=id[lcm(lcmlist[i],max(j,1))];
while(T--)
{
ll x;
scanf("%I64d",&x);
x--;
ll ans=0;
if (x)
{
n=0;
while(x)
{
s[++n]=x%10;
x/=10;
}
ans-=solve();
}
scanf("%I64d",&x);
n=0;
while(x)
{
s[++n]=x%10;
x/=10;
}
ans+=solve();
printf("%I64d\n",ans);
}
return 0;
}