题意

求[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. mysql数据库从删库到跑路之mysql库操作

    一 知识储备 MySQL数据库基本操作知识储备 数据库服务器:一台计算机(对内存要求比较高) 数据库管理系统:如mysql,是一个软件 数据库:oldboy_stu,相当于文件夹 表:student, ...

  2. Creating an AVI in memory with C++

    Creating an AVI in memory with C++        The following example demonstrates how an avi file is comp ...

  3. PKU 3318 Matrix Multiplication(神奇的输入)

    #include<cstdio> using namespace std; ][]; ][],C[][]; int Read() { ; ; while((ch=getchar())==' ...

  4. nginx配置访问图片路径(windows)

    简介 Nginx(("engine x")由俄罗斯的程序设计师Igor Sysoev所开发)是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.PO ...

  5. Winter-2-STL-F Ananagrams 解题报告及测试数据

    Time Limit:3000MS     Memory Limit:0KB  Description Most crossword puzzle fans are used to anagrams- ...

  6. Spring AOP 的实现方式(以日志管理为例)

    一.AOP的概念 AOP(Aspect Oriented Programming),是面向切面编程的技术.AOP基于IoC基础,是对OOP的有益补充,流行的AOP框架有Sping AOP.Aspect ...

  7. java并发内存模型

    java中线程之间的共享变量存储在主内存(java堆)中,每个线程都有一个私有的本地内存,本地内存存储了该线程以读.写共享变量的副本.本地内存是一个抽象概念,并不真实存储.它涵盖了cache,寄存器记 ...

  8. JS监听checkbox的选择获取取消事件代码案列

    function OncheckBox(index){ if ($(index).attr("checked") == "checked") { alert($ ...

  9. 20145316《Java程序设计》第十周学习总结

    学习内容总结 网络编程 1.网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据. 2.程序员所作的事情就是把数据发送到指定的位置,或者接收到指定的数据,这个就是狭义的网络编程范畴. 3.在发 ...

  10. iOS开发之XMPPFramework开发基础介绍

    1 使用iPhoneXMPP实例 2 修改xmppstream设置 3 基础协议的介绍 协议 协议简介 XEP-0009 在两个XMPP实体间传输XML-RPC编码请求和响应 XEP-0006 使能与 ...