魔法数字
题目描述
在数论领域中,人们研究的基础莫过于数字的整除关系。一般情况下,我们说整除总在两个数字间进行,例如 a | b(a能整除b)表示 b 除以 a 的余数为 0 。
我们称一个数字 X 是魔法的,当且仅当 X 是整数,且它能被 K 及 K 以上种一位数整除,要求这若干种一位数均在 X 的十进制表示中出现。
给出整数 K、L、R,请你计算出在区间 [L,R] 中,有多少个魔法数字。
输入格式
输入一行三个整数 K、L、R。
输出格式
输出一行一个整数,表示该区间内魔法数字的个数。
样例数据 1
输入
2 1 20
输出
2
备注
【数据范围】
对于 30% 的数据,1≤L≤R≤105;
对于 50% 的数据,1≤L≤R≤106;
对于 70% 的数据,1≤L≤R≤109;
对于 100% 的数据,1≤L≤R≤1018;0≤K≤9。
解析:
数位DP。f[ i ][ j ][ k ][ flag ]表示到第 i pos位, mod252等于 j,当前状态为k(二进制下),是否有限制的合法数量。
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL n,m,f[20][255][520][2];
int k,len,num[20],state[2550];
inline int calc(int s)
{
int sum=0;
while(s) sum++,s-=s&(-s);
return sum;
}
inline LL dfs(int pos,int mod,int stu,int flag)
{
if(pos > len)
{
mod -= mod / 2520 * 2520;
if(calc(state[mod] & stu) >= k) return 1;
return 0;
}
mod -= mod / 252 * 252;
if(~f[pos][mod][stu][flag]) return f[pos][mod][stu][flag];
int lim = flag ? num[pos] : 9;
LL sum=0;
for(int i=0;i<=lim;i++)
{
int xx;
flag && i == lim ? xx=1 : xx=0;
sum += dfs(pos+1,(mod<<1) + (mod<<3) + i,i == 0 ? stu : stu|(1<<(i-1)),xx);
}
return f[pos][mod][stu][flag] = sum;
}
inline LL solve(LL x)
{
memset(f,-1,sizeof(f));
len=0;
while(x) num[++len] = x - x / 10 *10,x/=10;
reverse(num+1,num+len+1);
return dfs(1,0,0,1);
}
int main()
{
for(int j=1;j<=9;j++)
for(int i=0;i<=2520;i++)
if(!(i % j)) state[i] |= 1<<(j-1);
scanf("%d%I64d%I64d",&k,&n,&m);
cout<<solve(m) - solve(n-1);
return 0;
}