codeforces55D(数位DP)
来源:互联网 发布:数据管理制度 编辑:程序博客网 时间:2024/04/29 17:00
地址:http://codeforces.com/problemset/problem/55/D
题意:找在区间内的beautiful number的数量,beautiful number的要求是概数能被其每一位数字整除。
思路:本来我想开四维数组,一个是数字位数,一个是首位数字,一个是各数位最小公倍数,一个是当前数字对这个最小公倍数的余数。这里有个难点在于如果最小公倍数改变了,那么以前保留的余数该怎么变化,所以要再开一维记录除数。但开5维数组不仅超空间,还超时间,所以就放弃了。看了下大神的优化,主要想法没变,但是处理起来就不一样了。建立三维数组,一个记录数字位数,一个记录各数位最小公倍数,一个记录当前几位数除以1~9的最小公倍数2520的余数。这里要开2520平方大的数组,太大了,所以离散一下1~9的最小公倍数,而且当前位数除以2520的余数可以看成当前位数除以252的余数(注意最后一位的处理)。这样既省时又省空间。
代码:
#include<iostream>#include<cstdio>#include<cmath>#include<cstring>using namespace std;#define LL __int64LL dp[20][50][255]; //三维记录数组int num[20],a[2550],b[255][10]={0};int gcd(int a,int b){ if(!b) return a; else return gcd(b,a%b);}int lcm(int a,int b){ return a*b/gcd(a,b);}LL dfs(int len,int m,int n,bool p) //len是数字位数,m是最小公倍数,n是对2520的余数{ if(!len) return n%m==0; if(!p&&dp[len][a[m]][n]>=0) return dp[len][a[m]][n]; int maxx=p?num[len]:9; LL ans=0; for(int i=0;i<=maxx;i++) ans+=dfs(len-1,i?lcm(m,i):m,len==1?n*10+i:b[n][i],i==maxx&p); if(!p) dp[len][a[m]][n]=ans; return ans;}LL getans(LL m){ int len=0; for(;m;m/=10) num[++len]=m%10; return dfs(len,1,0,1);}int main(){ memset(dp,-1,sizeof(dp)); for(int i=1,j=0;i<=2520;i++) a[i]=2520%i?0:++j; //对最小公倍数的离散 for(int j=0;j<10;j++) for(int i=0;i<252;i++) b[i][j]=(i*10+j)%252; //这里是处理余数 int t; LL m,n; scanf("%d",&t); while(t--) { scanf("%I64d%I64d",&m,&n); printf("%I64d\n",getans(n)-getans(m-1)); } return 0;}
0 0
- codeforces55D(数位DP)
- codeforces55D(离散化数位dp)
- codeforces55D. Beautiful numbers(数位dp+数论)
- CodeForces55D
- hdu3652(数位DP)
- hdu3709(数位dp)
- hdu4734(数位DP)
- ural1057(数位dp)
- lightoj1205(数位DP)
- hdu4352(数位DP)
- hdu4507(数位DP)
- hdu4734(数位DP)
- poj2282(数位dp)
- hdu3652(数位dp)
- hdu_3555_Bomb(数位DP)
- hdu4734(数位DP)
- hdu2089(数位dp)
- 数位dp(hdu2089)
- 考试系统的收获
- 蔡元培就职演讲
- Erlang基础 - 项式比较
- linux驱动杂项知识点
- Linux下Vim命令详解
- codeforces55D(数位DP)
- 读写(自旋)锁
- 安卓环境简单说明(一)
- python中的generator高级用法 -- send
- Struts2常用标签总结--转载
- SSE2介绍及其简单用法举例
- Linux环境变量设置
- 如何在windows下的Python开发工具IDLE里安装其他模块?
- 什么是线程安全函数?