数位dp

数位DP集合

ε祈祈猫儿з 提交于 2019-11-26 20:03:20
hdu2089不要62 #include<bits/stdc++.h> using namespace std; #define long long ll int a[20];//存数字 int dp[20][2]; int dfs(int count/*位数*/,int pre/*用于排除62的情况*/,int sta/*状态*/,bool limit/*判断是否有上限*/){ if(count == -1) return 1; if(!limit && dp[count][sta] != -1) return dp[count][sta];//退出递归 int up = limit ? a[count] : 9; int tmp = 0; for(int i = 0;i <= up;i++){ if(pre == 6 && i == 2)/*排除62的情况*/ continue; if(i == 4)/*排除4的情况*/ continue; tmp += dfs(count-1,i,i == 6,limit && i == a[count]); } if(!limit) dp[count][sta] = tmp; return tmp; } int solve(int x){//将数拆开存在数组里 int count = 0; while(x){ a[count++] = x

数位dp模板题--Round Numbers

元气小坏坏 提交于 2019-11-26 19:12:45
数位dp模板题–Round Numbers Round Numbers 。 题目大意: 给定一个区间(以十进制给出),计算出处于区间内数字的二进制形式中零的个数大于一的个数的数有几个。 首先数据给的2e9的,所以这题首先得思路就是用数位dp来做 思路: 将给定的数字以二进制的形式储存起来,设定三维的dp数组dp【当前位数】【一的个数】【零的个数】 记忆化搜索,跑DFS就能很轻松的解出来了 PS:这题需要特判前导零的情况。。。。。 #include<iostream> #include<string.h> using namespace std; int dp[101][51][51]; int digit[101]; ///digit数组储存搜索数字的二进制形式 int dfs(int pos,int num1,int num0,int limit,int lead) ///pos为当前位数,num1位当前1的个数,num0位当前0的个数,lead为特判的前导零的情况. { if(pos==-1) { if(num0>=num1) ///如果位数搜索完毕零的个数大于等于一的个数,这个数字符合条件,返回1,否则返回0 return 1; else return 0; } if(!lead&&!limit&&dp[pos][num1][num0]!=-1) ///对数据进行记忆化 {

DP(数位专题九)

半腔热情 提交于 2019-11-26 17:41:50
题意: 给定区间 [ l , r ] [l, r] [ l , r ] , 求该区间内每个数的数字和 >> face << Strategy: 别忘了取模 状态: d p [ i ] [ j ] dp[i][j] d p [ i ] [ j ] 目前搜到第i位该数的和为j 目标: $$ 边界: 本题无 合法判断: 条件转移合法判断 attention: 取模 双倍经验: 开longlong @author : jasonleft 记忆化数位 # include <bits/stdc++.h> # include <bits/extc++.h> # define _rep(i, a, b) for (ll i = (a); i <= (b); ++i) # define _rev(i, a, b) for (ll i = (a); i >= (b); --i) # define _for(i, a, b) for (ll i = (a); i < (b); ++i) # define _rof(i, a, b) for (ll i = (a); i > (b); --i) # define ll long long # define db double # define oo 0x3f3f3f3f # define eps 0.00001 # define all(x) x

DP(数位进阶二)

落花浮王杯 提交于 2019-11-26 17:31:59
题意: 给定区间, 求该区间内满足 说来也巧,位置在 i 的人面前的第 j 堆的石子的数量,刚好是 i 写成 K 进制后的第 j 位。现在方伯伯要玩一个游戏,商场会给方伯伯两个整数 L,R。 方伯伯要把位置在 [L, R] 中的每个人的石子都合并成一堆石子。每次操作,他可以选择一个人面前的两堆石子,将其中的一堆中的某些石子移动到另一堆,代价是移动的石子数量 * 移动的距离。 >> face << Strategy: 数位dp : 首先想一个问题, 对于一个人面前的石子, 怎样抉择才是最优的? 我们考虑"1,2,3", 如果我们把石子都集中在第一堆, 代价是 2 ∗ 1 + 3 ∗ 2 = 8 2*1+3*2 = 8 2 ∗ 1 + 3 ∗ 2 = 8 ,然后我们考虑集中在第二堆, 代价: 1 ∗ 1 + 3 ∗ 1 = 4 1*1 + 3*1 = 4 1 ∗ 1 + 3 ∗ 1 = 4 , 第三堆: 2 ∗ 1 + 2 ∗ 1 = 4 2*1+2*1 = 4 2 ∗ 1 + 2 ∗ 1 = 4 好像没啥规律, 不过可以得到启示: 当集合点从第一堆转成第二堆时, 变化可以看成 8 + 1 − 2 − 3 = 4 8+1-2-3= 4 8 + 1 − 2 − 3 = 4 , 于是可以得到推论, 从第i堆转移到第i+1堆时, 变化量是i的前缀和减去i+1的后缀和, 而且显然,

2019牛客多校第七场H Pair 数位DP

萝らか妹 提交于 2019-11-26 14:51:08
题意:给你一个3个数A, B, C问有多少对pair(i, j),1 <= i <= A, 1 <= j <= B, i AND j > C或 i XOR j < C。A, B, C范围为1e9. 思路:场上一看以为是推式子加什么筛做,无果。之后才知道是数位DP(以下思路来自学长的代码orz)。首先,我们可以把问题转化为求i AND j < C并且 i XOR j > C的数对个数,用总数(A* B)减去这个数。我们在DP过程中设置几个变量:ok1, 之前已经填的i 和 j的位是否已经满足i AND j < C, ok2同理。lim1表示i是否可以随便填,lim2同理。zero1表示上面填的位是否全是0,zero2同理。dp的时候,记忆化搜索就行。DP过程很直观就不解释了。(写了那么多数位DP赛场上想不到,太菜了QAQ) 代码: #include <bits/stdc++.h> #define LL long long using namespace std; const int maxn = 55; int a[maxn], b[maxn], c[maxn]; LL dp[maxn][2][2][2][2][2][2]; LL dfs(int dep, bool ok1, bool ok2, bool lim1, bool lim2, bool zero1, bool zero2

数位dp相关

旧城冷巷雨未停 提交于 2019-11-26 12:08:31
经典的数位Dp是要求统计符合限制的数字的个数。 一般的形式是:求区间[n,m]满足限制f(1)、 f(2)、 f(3)等等的数字的数量是多少。 条件 f(i) 一般与数的大小无关,而与数的组成有关。 善用不同进制来处理,一般问题都是10进制和二进制的数位dp。 数位dp的部分一般都是很套路的,但是有些题目在数位dp外面套了一个华丽的外衣,有时我们难以看出来。 直接就上的例题: HDU3652 统计区间[1,n]中含有'13'且模13为0的数字有多少个。 N<=1e9; 咋做?不急,先从简化版的找规律; HDU3652简化版 统计区间 [1,n] 中含有 '3' 的数字有多少个。 N=x_1 x_2 x_3 x_4….. x_total 。 x_i为n的从高到低第i位是多少。 Total是总的位数。 如果我们考虑从高到低位不断填数y_1 y_2 …。那么问题其实就是问有多少填数的方案,一要满足上限的限制(对应区间[1,n]),二要满足题目的其他限制。 这样其实就比[1,n]看起来更能dp了 假设到了第k位y_k!=x_k,则k位之后就没有上限的限制了,情况就简化了。 如果前面y中没有出现3:那么假如我们可以求出来, f[k][0]表示k位之后没有上限限制(随意填),但是必须填个3(前面没有出现),有多少种填数的方案。 如果前面y中出现了3:那么假如我们可以求出来, f[k][1

清北学堂2019.8.7

纵饮孤独 提交于 2019-11-26 10:17:31
Day 2 赵和旭 今天以背包DP,数位DP,树形DP和基环树为主(好多啊) 背包问题 0/1 背包问题 给出 n 个物品,每个物品有 Vi 的价值和 Wi 的费用,我们总共有 m 块钱,求最多能得到多少价值的物品。 N<=10^3,m<=10^3 memset(dp,-0x3f,sizeof(dp)); dp[0][0]=0; for (int i=1;i<=n;i++) { for (int j=0;j<w[i];j++) dp[i][j]=dp[i-1][j]; for (int j=w[i];j<=m;j++) dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]); } 更简便更省空间更常用的写法 memset(f,-0x3f,sizeof(f)); f[0]=0; for (int i=1;i<=n;i++) for(int j=m;j>=w[i];j--) f[j]=max(f[j],f[j-w[i]]+v[i]); 设 dp[i][j] 表示前 i 个物品,用了 j 的体积得到的最大的价值。 则 dp[i][j]=max{dp[i-1][j] , dp[i-1][j-w[i]]+v[i]} 若求方案数:   dp[i][j]=dp[i-1][j]+dp[i-1][j-w[i]] 完全背包 每一个物品可以选无限个。 dp[i][j]

DP&图论 DAY 2 上午

若如初见. 提交于 2019-11-26 10:03:04
DP&图论 DAY 2 上午 背包DP模型 >背包DP ◦ 一般是给出一些“物品 ” ,每个物品具有一些价值参数和花费参数,要求 在满足花费限制下最大化价值或者方案数。 ◦ 最简单几种类型以及模型 ◦ 0/1 背包 ◦ 完全背包 ◦ 多重背包 > 0/1 背包问题 ◦ 给出 n 个物品,每个物品有 Vi 的价值和 Wi 的费用,我们总共有 m 块钱,求 最多能得到多少价值的物品。 ◦ N<=10^3,m<=10^3 >Solution ◦ 设 dp[i][j] 表示前 i 个物品,用了 j 的体积得到的最大的价值。 ◦ 则 dp[i][j]=max{dp[i-1][j] , dp[i-1][j-w[i]]+v[i]} ◦ 复杂度 O(N*M) ◦ 如果要记录方案数呢? ◦ 如果要求输出方案呢? >在有价值情况下求方案数?? 原来的式子是dp[i][j]=max{dp[i-1][j] , dp[i-1][j-w[i]]+v[i]} ,dp[ ][ ] 是最大价值 现在设方案数为 f[ ][ ] 如果dp[i-1][j] > dp[i-1][j-w[i]]+v[i] ,那么就会选择第一种转移过来 如果dp[i-1][j] < dp[i-1][j-w[i]]+v[i] ,那么就会选择第二种转移过来 所以 f[i][j]=max(f[i-1][j],f[i-1][j-wi]} 如果dp[i

背包&数位dp(8.7)

筅森魡賤 提交于 2019-11-26 09:03:00
背包 0/1背包 设dp[i][j]为前i个物品选了j体积的物品的最大价值/方案数 dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j])(最大价值) dp[i][j]=dp[i-1][j-w[i]]+dp[i-1][j](方案数) 输出方案: dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]) 看方程,我们可以记录第i个物品选不选,如果选,再递归到dp[i-1][j-w[i]]即可 有价值的情况下记录最优策略方案数 ①:dp[i-1][j]≠dp[i-1][j-w[i]]:dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]) ②:dp[i-1][j]==dp[i-1][j-w[i]]:dp[i][j]=dp[i-1][j]+dp[i-1][j-w[i]] 两种写法: 完全背包 多重背包 两种写法: 然后还有什么二进制优化是吧 就是把第i种物品按照t[i]的二进制拆分来打包 举个例子:t[i]=5,二进制:101 那就打成有四个物品的包和有一个物品的包 四个物品的包的体积是4*w[i],价值是4*v[i] 当t[i]不是2 m 怎么办? 放心任何一个数都可以用二进制表示出来(就是进行一些特殊处理) 这样就可以拆成logt[i]个包 然后当0/1背包搞就好了

「动态规划」-数位dp专题

Deadly 提交于 2019-11-25 16:54:13
数位dp,今天学长讲的稍玄学,课下花了一会时间仔细看了一下,发现板子是挺好理解的,就在这里写一些: 数位dp主要就是搞一些在区间中,区间内的数满足题目中的条件的数的个数的一类题,题目一般都好理解,这时候就要使用今天介绍的数位dp; 比如这道例题: 给定两个正整数a和b,求在[a,b]中的所有整数中,每个数字各出现了多少次。 求出在给定区间 [A,B] 内,符合条件 f(i) 的数 i 的个数。条件 f(i) 一般与数的大小无关,而与数的组成有关 由于数是按位dp,数的大小对复杂度的影响很小,这就是数位dp干的活! 题目看起来很简单,然后让我们做,我们会怎么做呢?反正我在没有学数位dp的时候当然是暴力枚举了,不用看1e12的数据范围一定会T到飞起,那我们怎么办呢?那就先让我来介绍一下数位dp吧! 数位dp的本质其实就是记忆化搜索,所以我们只要按照搜索的思路来做就好了! 我们来想一想如何设计这个搜索 ? 这个搜索,其实我感觉就像我们在考场上打的dfs暴力,记忆化搜索的过程就是 从起点向下搜索,到最底层得到方案数,一层一层向上返回答案并累加,最后从搜索起点得到最终答案。 对于 [l,r] 区间问题,我们一般把他转化为两次数位dp,即找 [0,r] 和 [0,l-1] 两段,再将结果相减就得到了我们需要的 [l,r]; 所以这里的第一个套路就是遇见区间就要想前缀和! 如果理解了上述过程