CodeForces - 55D Beautiful numbers
题目链接:https://vjudge.net/problem/CodeForces-55D
题意:求l到r中有多少个数可以整除自己的每个非零数位。
思路:一个数可以整除它所有非0位数,那它要能整除所有位数的公倍数才行。然后1,2,3,.....9,10的最小公倍数是2520,然后就直接用数位dp。但开不了dp[25][2520][2520]那么大的数组,可以离散化一下,只要知道2520的因数即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[25][2530][50];
int a[25],b[2530];
int mod=2520;
int gcd(int x,int y)
{
while(y)
{
int z=x%y;
x=y;
y=z;
}
return x;
}
int lcm(int x,int y)
{
return x*y/gcd(x,y);
}
//len:位数 ans:数的大小 sum:公倍数 flag:是否处于上边界
ll dfs(int len,int ans,int sum,bool flag)
{
if(len==0)
return ans%sum==0;
int up=flag?a[len]:9;
if(!flag&&dp[len][ans][b[sum]]!=-1)
return dp[len][ans][b[sum]];
ll tmp=0;
for(int i=0; i<=up; i++)
{
if(i==0)
tmp+=dfs(len-1,(ans*10+i)%mod,sum,flag&&i==a[len]);
else
tmp+=dfs(len-1,(ans*10+i)%mod,lcm(sum,i),flag&&i==a[len]);
}
if(!flag)
dp[len][ans][b[sum]]=tmp;
return tmp;
}
ll suan(ll x)
{
int pos=0;
while(x)
{
a[++pos]=x%10;
x/=10;
}
return dfs(pos,0,1,true);
}
void inif()
{
int v=0;
for(int i=1;i<=2520;i++)
{
if(2520%i==0)
b[i]=++v;
}
}
int main()
{
inif();
memset(dp,-1,sizeof(dp));
int t;
cin>>t;
while(t--)
{
ll l,r;
cin>>l>>r;
cout<<suan(r)-suan(l-1)<<endl;
}
}
浙公网安备 33010602011771号