题意

求[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]

最新文章

  1. PHP基础知识之逻辑运算符
  2. redis的数据类型和指令
  3. getResourceAsStream和getResource的用法及Demo实例
  4. Win7 64位下PowerDesigner连接64位Oracle11g数据库
  5. touch移动触屏滑动事件
  6. linux中预留的$变量
  7. Linux_05------Linux之vim编辑器
  8. 正向代理与反向代理的区别【Nginx读书笔记】(zz)
  9. 将32位MD5摘要串转换为128位二进制字符串
  10. HDU 5724:Chess(博弈 + 状压)
  11. 理论沉淀:隐马尔可夫模型(Hidden Markov Model, HMM)
  12. 为什么要重写equals()方法与hashCode()方法
  13. ES6第一篇
  14. (2)ES6解构赋值-数组篇
  15. cocos2dx - v2.3.3编辑器简单使用及不同分辨率适配
  16. StickyListHeaders的使用
  17. OSPF 基础实验
  18. asp.net core 系列 7 Razor框架路由(上)
  19. Sql 无法解决 equal to 运算中 &quot;Chinese_PRC_CI_AS&quot; 和 &quot;Chinese_PRC_90_CI_AI&quot; 之间的排序规则冲突
  20. 「2017 山东三轮集训 Day7 解题报告

热门文章

  1. SQL Server去重和判断是否为数字——OBJECT_ID的使用
  2. BFC 详说 Block Formatting Contexts (块级格式化上下文)
  3. 54. Spiral Matrix(矩阵,旋转打印)
  4. Spring 实现数据隔离
  5. servlet中通过getWriter()获取out返回给浏览器出现中文乱码问题
  6. Qt 编码问题QTextCodec
  7. iis日志时间与本地日期不一样
  8. 【Thinking in Java, 4e】访问权限控制
  9. jQuery中this 和 $(this)
  10. [pixhawk笔记]7-MAVLink添加自定义消息