DP·数位DP(2)
来源:互联网 发布:承接淘宝服装代加工 编辑:程序博客网 时间:2024/06/07 20:24
题目:
CodeForces 55D
题意:
若一个数能被其各个位上的数整除,即满足条件。求区间[l, r]内所有满足条件的数
方法:
若想要一个数能被其各个数位上的数整除,则此数要能被各个位上的数的LCM整除。而且由于LCM(1~9) = 2520,所以将数对2520取模后,若余数能被LCM整除,则原数也能被LCM整除,因为LCM肯定为2520的一个因子。
(期初几个数位DP都是用循环写的,结果后来发现有dfs的更具普遍应用的写法,更容易理解且能被更广地使用,虽然速度肯定不如循环的写法……但胜在简单实用)
数位DP,通过[l, r] = [1,r]- [1,l-1]求得最终答案(其实此方法也可以看成一种记忆化搜索,只是通过数位DP的思想优化了状态,减少了大量的复杂度)
定义状态:dfs(int n, int lcm, int m, bool flag)表示当前为第n位,之前所有位的LCM为lcm,且对之前构造出来的数对2520取模后为m,flag表示之前枚举的数知否全部到达上限(对于4567,则4512的前两位到达上限),即当前枚举的数是否受限
初始状态:dfs(len,1, 0, true)。
状态转移:
1若n为0,则枚举完了整个数列,返回m% lcm == 0。
2若之前所有数都达到了上限,即flag为true,则此位置可枚举的数为0~num[n](表示原数的第n位)
3若之前的数中有一个没到上限,则此位置无论是什么数,都不可能比原数大(类似循环的数位DP那个思想),则此位置可枚举的数为0~9
优化:由于1~9的数组合成的LCM是离散的,所以通过离散化lcm可减少空间复杂度。通过一个f[n][lcm][m]的数组进行记忆存储,减少时间复杂的,此数组存的是当长度为n,LCM为lcm,余数为m时所有满足条件的数的个数,所以要直接返回f数组的值时,不仅需要f数组的值存在,还要flag为false,即此时不受限
PS:由于第一次f数组开成了f[n][m][lcm]……结果调试了半天……算是自己把自己又坑了一回
测试数据:
2
1 1000
1 10000
答案:
138
752
#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<string>#include<algorithm>#include<climits>#include<cstdlib>using namespace std;//#define DEBUGconst int MAXMOD = 2520;typedef __int64 ll;ll f[20][50][MAXMOD+100];int h[MAXMOD+100];int num[20];ll xGcd(ll a, ll b){return (a % b == 0)? b:xGcd(b, a % b);}ll xLcm(ll a, ll b){return a / xGcd(a, b) * b;}ll dfs(int n, int lcm, int m, bool flag){#ifdef DEBUGcout<<"n="<<n<<" flag"<<((flag)? 1:0)<<endl;#endifif ( !n ) return m % lcm == 0;if ( ~f[n][h[lcm]][m] && !flag ) return f[n][h[lcm]][m];int k = (flag? num[n]:9);#ifdef DEBUGcout<<"k="<<k<<endl;#endifll ans = 0;for (int i = 0; i <= k; i++){int cLcm = (i)? xLcm(lcm, i):lcm;int cM = (m * 10 + i) % MAXMOD;ans += dfs(n - 1, cLcm, cM, flag && (i == k));}if ( !flag ) f[n][h[lcm]][m] = ans;return ans;}ll getAns(ll a){#ifdef DEBUGcout<<"num="<<a<<endl;#endifint len = 0;while ( a ) num[++len] = a % 10, a /= 10;#ifdef DEBUGfor (int i = len; i; i--) cout<<num[i]<<" ";cout<<endl;cout<<"dfs="<<dfs(len, 1, 0, true)<<endl;#endifreturn dfs(len, 1, 0, true);}int main(){//freopen("in.txt", "r", stdin);int cn = 0;for(int i = 1; i <= MAXMOD; i++) if ( MAXMOD % i == 0 ) h[i] = cn++;#ifdef DEBUGcout<<"cn="<<cn<<endl;#endifmemset(f, -1, sizeof(f));int T;scanf("%d", &T);while ( T-- ){ll l, r;scanf("%I64d%I64d", &l, &r);printf("%I64d\n", getAns(r) - getAns(l-1));} return 0;}
- DP·数位DP(2)
- DP·数位DP
- DP·数位DP(4)
- DP·数位DP(5)
- DP·数位DP(3)
- hdu3652(数位DP)
- hdu3709(数位dp)
- codeforces55D(数位DP)
- hdu4734(数位DP)
- ural1057(数位dp)
- lightoj1205(数位DP)
- hdu4352(数位DP)
- hdu4507(数位DP)
- hdu4734(数位DP)
- poj2282(数位dp)
- hdu3652(数位dp)
- hdu_3555_Bomb(数位DP)
- hdu4734(数位DP)
- (1.4.10) 迅雷2014校园招聘笔试题
- CSS 入门
- ZOJ 3870 - Team Formation(数学)
- Qt 实现的文本编辑器
- MySql的基本语句操作
- DP·数位DP(2)
- 二分查找
- 利用反射技术修改类中的字段(成员变量的反射)
- Linux常用命令大全
- hihoCoder 1038 : 01背包
- 数据挖掘数据集下载搜集整理版
- day 024UITableView
- 深入了解 CSS3 新特性
- B_Dungeon Master(POJ_2251)