题意

求[X,Y]区间内能被其各位数(除0)均整除的数的个数。

CF 55D

有些时候因为问题的一些“整体性”而导致在按位统计的过程中不能顺便计算出某些量,所以只能在枚举到最后一位确定数字时才能计算相应的统计。

在本题中,我们无法在过程中确定到底有哪些数位,以及这个数本身,所以这些计算都要放在最后。所以首先我们需要参数num传递当前搜索确定的数字,以及判断该数字是否能被其数位整除。而判断各位整除只要数字整除各位数的最小公倍数lcm即可。

但我们随后发现了问题:各位数最小公倍数最大可能为lcm(1..9)=2520,而某个数最大为1018显然不能直接存。当然,我们可以用这个数%2520来代替数本身,但这样2520*2520*20的空间也不够。我们可以发现其实各位数的最小公倍数远没有2520个,而是2520的所有约数个数,不到50个。所以我们可以利用hash将空间缩至2520*50*20。这样,CF 55D便迎刃而解了(详见下面CF 55D代码)。

SPOJ JZPEXT

再来看CF 55D的升级版……两道都是7k+出的题只是这道更丧心病狂……全世界只有21个人AC……题目本身并没有变,只是限制了代码长度为1k!并且,数据组数增至104!

首先需要的是强劲的缩代码能力,这个不说了。我们发现,其实每个数2520的空间也浪费了,每次向下枚举一位都是(rem * 10 + i) mod 2520。。那么到最后一位的时候先给了之前的数2和5两个因子。。整个能不能多整除一个2和5只取决于i。。因此。。之前只需要记录模252的余数就可以了。。

最后需要注意的是需要把lcm和(rem*10+i)%252都预处理一下……

代码

【CF 55D】
[cpp]
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define MEM(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
int num[20], hash[2550];
LL dp[20][2550][55];
int gcd(int a, int b){
return b?gcd(b, a%b):a;
}
int cal_lcm(int a, int b){
return a/gcd(a, b)*b;
}
void init(){
MEM(dp, -1);
int n=2520, id=0;
for (int i = 1; i*i <= n; i ++){
if (n%i==0){
hash[i] = id++;
if (i != n/i){
hash[n/i] = id ++;
}
}
}
}
LL dfs(int pos, int mod, int lcm, bool limit){
if (pos == -1) return (mod%lcm==0);
if (!limit && ~dp[pos][mod][hash[lcm]]) return dp[pos][mod][hash[lcm]];
int end = limit?num[pos]:9; LL res = 0;
for (int i = 0; i <= end; i ++){
res += dfs(pos-1, (mod*10+i)%2520, i?cal_lcm(lcm, i):lcm, limit && (i==end));
}
return limit?res:dp[pos][mod][hash[lcm]]=res;
}
LL cal(LL x){
int i = 0;
while(x){
num[i++] = x%10;
x/=10;
}
return dfs(i-1, 0, 1, 1);
}
int main(){
init();
int t;
scanf("%d", &t);
while(t --){
LL l, r;
scanf("%lld %lld", &l, &r);
printf("%lld\n", cal(r)-cal(l-1));
}
return 0;
}
[/cpp]
【SPOJ JZPEXT】
[cpp]
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int nu[20],h[2522],mo[255][10],mu[255][10],lc[2522][10];
LL f[20][55][255];
LL dfs(int p,int m,int l,bool li){
if(p==-1)return (m%l==0);
if(!li && ~f[p][h[l]][m]) return f[p][h[l]][m];
int e=li?nu[p]:9;LL r=0;
for (int i=0;i<=e;i++){r+=dfs(p-1,p?mo[m][i]:mu[m][i],lc[l][i],li&&(i==e));}
return li?r:f[p][h[l]][m]=r;
}
LL cal(LL x){
int i=-1;
while(x){nu[++i]=x%10;x/=10;} ++i;
return dfs(i-1,0,1,1);
}
int main(){
memset(f,-1,sizeof(f));
int i,j,id=0;
for (i=0;i<=252;i++)for (j=0;j<10;j++){mu[i][j]=i*10+j;mo[i][j]=mu[i][j]%252;}
for (i = 0; i <= 2520; i ++){
if (i>0 && 2520%i==0){h[i]=id++;}
for(j=0;j<10;j++)lc[i][j]=j?i*j/__gcd(i,j):i;
}
int t;
scanf("%d",&t);
while(t--){
LL l,r;
scanf("%lld%lld",&l,&r);
printf("%lld\n",cal(r)-cal(l-1));
}
return 0;
}
[/cpp]

CodeForces 55D Beautiful numbers (SPOJ JZPEXT 数位DP)的更多相关文章

  1. CodeForces 55D "Beautiful numbers"(数位DP+离散化处理)

    传送门 参考资料: [1]:CodeForces 55D Beautiful numbers(数位dp&&离散化) 我的理解: 起初,我先定义一个三维数组 dp[ i ][ j ][ ...

  2. Codeforces 55D. Beautiful numbers(数位DP,离散化)

    Codeforces 55D. Beautiful numbers 题意 求[L,R]区间内有多少个数满足:该数能被其每一位数字都整除(如12,24,15等). 思路 一开始以为是数位DP的水题,觉得 ...

  3. codeforces 55D - Beautiful numbers(数位DP+离散化)

    D. Beautiful numbers time limit per test 4 seconds memory limit per test 256 megabytes input standar ...

  4. CodeForces - 55D - Beautiful numbers(数位DP,离散化)

    链接: https://vjudge.net/problem/CodeForces-55D 题意: Volodya is an odd boy and his taste is strange as ...

  5. CodeForces - 55D Beautiful numbers —— 数位DP

    题目链接:https://vjudge.net/problem/CodeForces-55D D. Beautiful numbers time limit per test 4 seconds me ...

  6. CodeForces 55D Beautiful numbers(数位dp+数学)

    题目链接:http://codeforces.com/problemset/problem/55/D 题意:一个美丽数就是可以被它的每一位的数字整除的数. 给定一个区间,求美丽数的个数. 显然这是一道 ...

  7. CodeForces 55D Beautiful numbers(数位dp)

    数位dp,三个状态,dp[i][j][k],i状态表示位数,j状态表示各个位上数的最小公倍数,k状态表示余数 其中j共有48种状态,最大的是2520,所以状态k最多有2520个状态. #include ...

  8. Codeforces - 55D Beautiful numbers (数位dp+数论)

    题意:求[L,R](1<=L<=R<=9e18)区间中所有能被自己数位上的非零数整除的数的个数 分析:丛数据量可以分析出是用数位dp求解,区间个数可以转化为sum(R)-sum(L- ...

  9. CodeForces 55D Beautiful numbers

    D. Beautiful numbers time limit per test 4 seconds memory limit per test 256 megabytes input standar ...

随机推荐

  1. python全栈开发从入门到放弃之socket并发编程多线程

    一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 二 开启线程的两种方式 from threadi ...

  2. ACM-ICPC 2018 焦作赛区网络预赛 F. Modular Production Line (区间K覆盖-最小费用流)

    很明显的区间K覆盖模型,用费用流求解.只是这题N可达1e5,需要将点离散化. 建模方式步骤: 1.对权值为w的区间[u,v],加边id(u)->id(v+1),容量为1,费用为-w; 2.对所有 ...

  3. How can For each...

    Answer:   I understand the IEnumerator/IEnumerable methods and properties and also how they are inte ...

  4. 20145316《Java程序设计》第六周学习总结

    20143516许心远 <Java程序设计>第6周学习总结 教材学习内容总结 10.1.1 1.Java将输入/输出抽象化为串流,数据有来源及目的地,衔接两者的是串流对象. 2.若要将数据 ...

  5. C++之条形码,windows下zint库的编译及应用(一)

    zint库是一个开源的第三方库,提供了生成条形码.二维码等功能.本文主要介绍zint库的生成及简单应用. 工具/原料   vs2012 代码文件下载   1 下载zint包 2 zint依赖另外两个库 ...

  6. 【Python】高阶函数

    filter def is_palindrome(n): L = str(n) i = 0 j = len(L) - 1 while i != j: if L[i] != L[j]: return F ...

  7. 【C#】枚举和字符串以及数字之间的互相转换

    准备条件: ①枚举类型: public enum enumColor { Red = , Yellow, Green, Blue, White, Black } ②以下状态都是理想状态,并未对错误数据 ...

  8. KALI视频学习11-15

    KALI视频学习11-15 第十一集 看到openvas的主界面(web界面) ping靶机,看是否能正常连通 创建一个扫描目标Configuration-Targets,默认扫描目标为本机 添加一个 ...

  9. Excel水平线画不直,图形对象对不齐,怎么办

    看够了千篇一律的数字报表,不妨添加些图形对象来调剂下,今天小编excel小课堂(ID:excel-xiaoketang 长按复制)给各位分享10个插入图形对象时简单实用的小技巧. 01课题 今天小编e ...

  10. Jquery7 表单选择器

    学习要点: 1.常规选择器 2.表单选择器 3.表单过滤器 表单作为 HTML 中一种特殊的元素,操作方法较为多样性和特殊性,开发者不但可以使用之前的常规选择器或过滤器,也可以使用 jQuery 为表 ...