【NOIP模拟】魔法数字

                                                         魔法数字

题目描述

在数论领域中,人们研究的基础莫过于数字的整除关系。一般情况下,我们说整除总在两个数字间进行,例如 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;
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/81269403