数位dp

BZOJ4513: [Sdoi2016]储能表(数位dp)

匿名 (未验证) 提交于 2019-12-02 23:03:14
题目链接 Sol 一点思路都没有,只会暴力,没想到标算是数位dp??Orz 首先答案可以分成两部分来统计 设 \[ f_{i,j}= \begin{aligned} i\oplus j &\left( i\oplus j >k\right) \\ 0 &\left( i\oplus j <=k\right) \end{aligned} \] 那么我们要求的就是 \[\sum_{i=0}^{n - 1} \sum_{j = 0}^{m - 1} f(i, j) - k * \sum_{i = 0}^{n - 1} \sum_{j = 0}^{m - 1} [f(i, j)]\] 也就是说,我们要统计出满足条件的数的异或和以及满足条件的数的对数 考虑直接在二进制下数位dp,注意这里我们要记三维状态 \(f[len][0/1][0/1][0/1]\) 表示此时到第 \(len\) 位,是否顶着 \(n\) 的上界,是否顶着 \(m\) 的上界,是否顶着 \(k\) 的下界 然后直接dp就可以了 // luogu-judger-enable-o2 #include<bits/stdc++.h> #define Pair pair<LL, LL> #define MP make_pair #define fi first #define se second #define LL long

最短Hamilton路径 数位dp

假如想象 提交于 2019-12-02 21:59:26
最短Hamilton路径 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 21; 4 int dp[1<<maxn][maxn]; 5 int maps[maxn][maxn]; 6 int main() { 7 int n; cin >> n; 8 for (int i = 0; i < n; i++) 9 for (int j = 0; j < n; j++) 10 cin >> maps[i][j]; 11 memset(dp,0x3f3f3f3f,sizeof(dp)); 12 dp[0][0] = 0; 13 for (int i = 0; i < (1<<n); i++) { 14 for (int j = 0; j < n; j++) { 15 if ((i>>j)&1) { 16 for (int k = 0; k < n; k++) { 17 if ((i>>k)&1) 18 dp[i][j] = min(dp[i][j],dp[i^(1<<j)][k]+maps[k][j]); 19 } 20 } 21 } 22 } 23 printf("%d\n",dp[(1<<n)-1][n-1]); 24 return 0; 25 } 来源: https://www.cnblogs

hdu2089 不要62 数位dp

时光总嘲笑我的痴心妄想 提交于 2019-12-02 19:56:19
hdu2089 不要62 1 #include <bits/stdc++.h> 2 using namespace std; 3 int dp[15][15], d[15]; 4 void init() { 5 dp[0][0] = 1; 6 for (int i = 1; i <= 7; i++) { 7 for (int j = 0; j <= 9; j++) { 8 for (int k = 0; k <= 9; k++) { 9 if (j != 4 && !(j == 6 && k == 2)) { 10 dp[i][j] += dp[i-1][k]; 11 } 12 } 13 } 14 } 15 } 16 int solve(int n) { 17 int ans = 0, len = 0; 18 while (n) { 19 ++len; 20 d[len] = n%10; 21 n /= 10; 22 } 23 d[len+1] = 0; 24 for (int i = len; i >= 1; i--) { 25 for (int j = 0; j < d[i]; j++) { 26 if (d[i+1] != 6 || j != 2) { 27 ans += dp[i][j]; 28 } 29 } 30 if (d[i] == 4 || (d[i+1] == 6

数位DP

白昼怎懂夜的黑 提交于 2019-12-02 09:11:22
数位DP 概念 数位DP就是一种用于计数的dp, 一般用于统计区间[l, r]中符合条件的数的个数。所谓数位dp,就是在各个数位上进行dp。之所以引入dp的概念,其实是为了进行统计。数位dp的实质其实就是一种暴力枚举,但这种枚举方式满足dp的性质,然后进行记忆化搜索就行了。 而这种枚举大概有两种方式,第一种: for ( int i = l ; i <= r ; ++ i ) if ( check ( i ) Ans ++ ; 新的枚举:控制上界枚举,从最高位开始往下枚举,例如:r = 213,那么我们从百位开始枚举:百位可能的情况有0, 1, 2 (0 等会会处理) 然后每一位枚举都不能让枚举的这个数超过上界213(下界就是0或者1,这个次要),当百位枚举了1,那么十位枚举就是从0到9,因为百位1已经比上界2小了,后面数位枚举什么都不可能超过上界。所以问题就在于:当高位枚举刚好达到上界是,那么紧接着的一位枚举就有上界限制了。具体的这里如果百位枚举了2,那么十位的枚举情况就是 0 ~ 1 ,如果前两位枚举了 2, 1,最后一位之是 0 ~ 3 (这一点正好对于代码模板里的一个变量 limit 专门用来判断枚举范围)。最后一个问题: 最高位枚 0, 百位枚举 0,相当于此时我枚举的这个数最多是两位数,如果十位继续枚举0,那么我枚举的就是以为数咯,因为我们要枚举的是小于等于 r

[CSP校内集训]reverse(数位DP)

ぃ、小莉子 提交于 2019-12-02 06:45:18
题意 给一个范围[L,R],求满足 \(L\leq n \leq R\) 且 \(L\leq rev(n) \leq R\) 的 \(n\) 的个数,其中 \(rev(n)\) 表示将 \(n\) 翻转 \((123->321)\) ,多组询问 \((L,R\leq 2^64-1)\) 思路 长这样的计数问题,没什么悬念考虑数位DP 只设 \(f_{i,lim}\) 表示处理到第 \(i\) 位是否顶上界似乎不太够,因为在转移过程中还需要知道倒过来的数的状态,所以再用个变量 \(lim2\) 记录倒过来的数的状况 因为从前向后确定数倒过来看是从后向前确定数,所以 \(lim2\) 有三个值:比当前上界小,顶上界,暂时大于上界,用 \(0,1,2\) 表示 仅仅这样做并不能很好的处理前缀0的情况(如0001倒过来看会变成1000,但实际上应该为1),所以我还用了一个变量 \(zer\) 表示第一个 非零 数出现的位置 状态即为 \(f_{i,lim1,lim2,zer}\) ,一遍数位DP即可求出答案,递归边界返回值为1的条件为 \(lim2 \neq 2\) 或 倒过来的限制R的位数比L多1 本题毒瘤, \(L,R\) 会炸longlong,需要用unsigned longlong来做,随时都需要注意爆边界的情况qwq 考试的标程都是错的几个意思 #include<bits

P2657 [SCOI2009]windy数 (数位DP)

纵饮孤独 提交于 2019-12-01 11:30:09
题目地址 注意点: 边界讨论. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int INF=2e9; 7 int dp[15][15]; 8 int num[15];//每一位数字的最大值 9 int dfs(int len,int last,bool isMaxed,bool lead){//lead: 是否有前导零 10 if(len==0)return 1;//递归边界 11 if(!lead&&!isMaxed&&dp[len][last]) 12 return dp[len][last]; 13 int cnt=0; 14 int nowMaxVal=(isMaxed?num[len]:9);//当前位最大值 15 for(int i=0;i<=nowMaxVal;i++){//枚举当前位数字 16 if(abs(i-last)<2)continue; 17 int nowNum=i;//当前位数字 18 if(lead&&i==0)nowNum=-INF;//继续增加前导零 19 cnt+=dfs(len-1,nowNum,(isMaxed)&&(i==nowMaxVal),(nowNum=

数位dp学习笔记

匆匆过客 提交于 2019-12-01 10:01:18
目录 数位dp学习笔记 引入 练习题目 LG2567 ZJOI2010 LG3413 后记 数位dp学习笔记 在解决一类数位问题的时候,我们发现有些状态是多余的(比如中间的某些数),完全可以合并一起计数,这就是数位dp 具体地说,按每一位进行dp,枚举长度和与要用到的数字 引入 一道例题:求n位数中能被m整除的个数 定义一个状态: \(f[i][j]\) 表示当前是第 \(i\) 位,除以 \(m\) 的余数为 \(j\) 初始情况: \(f[1][i]=1(1\leq i \leq 9)\) 对于下一位 \(k\) ,余数变成 \(j*10+k \pmod m\) 转移就是 \(f[i+1][(j*10+k) \pmod m]+=f[i][j]\) 由于最后要求倍数,答案为 \(f[n][0]\) 练习题目 LG2567 求[L,R]中不含前导零且相邻两个数字之差至少为2的正整数 考虑求出前缀和 由于前导0比较🤢,我们从低往高进行dp 设计状态: \(f[i][j]\) 表示 \(i\) 位数,最高位为 \(j\) 的windy数个数 预处理出来之后分成三部分计算答案: 位数都小于此数 位数等于此数,但是最高位小于此数(前导0,不能和3合并) 位数等于次数,最高位也相等,考虑枚举有多少位相等 其实有前导0的都可以这样搞计数,只是预处理方法不同 ZJOI2010 \(f[i][j]

模拟测试66

我们两清 提交于 2019-12-01 06:38:12
T1:   每行每列都可以交换,其实就是错位排列。   写出递推式,打个高精就行了。     $f_n=(f_{n-1}+f_{n-2})*(n-1)$。   时间复杂度$O(nc)$。 T2:   可以暴力用bitsetAC。   直接建图跑拓扑,判断所有点的入度和能到达它的的点数是否相同。   用bitset维护连通集合。   若图Q是传递的,对于P中的每一条边$<u,v>$,一定不存在$u$到$v$的通路,否则与Q传递矛盾。   也就是说,仅当总的图无环,才满足条件。   直接拓扑排序即可。   时间复杂度$O(n^2)$。 T3:   数位DP。 来源: https://www.cnblogs.com/hz-Rockstar/p/11655798.html

## 数位DP模板

懵懂的女人 提交于 2019-11-30 19:33:38
数位DP模板 int l,r,len,...; int dp[][][][]...; int bit[]; inline int dfs(int pos,int pre,int st,……,bool lead,bool limit){ if(pos>len) return st;//剪枝 if((dp[pos][pre][st]……[……]!=-1&&(!limit)&&(!lead))) return dp[pos][pre][st]……[……];//记录当前值 int res=0;//暂时记录当前方案数 int res=limit?bit[len-pos+1]:9;//res当前位能取到的最大值 for(int i=0;i<=res;i++){ //有前导0并且当前位也是前导0 if(i==0 && lead) ret+=dfs(……,……,……,i==res&&limit); //有前导0但当前位不是前导0,当前位就是最高位 else if(i && lead) ret+=dfs(……,……,……,i==res&&limit); else if(根据题意而定的判断) ret+=dfs(……,……,……,i==res&&limit); } if(!limit && !lead) dp[pos][pre][st]……[……]=res;//当前状态方案数记录 return res;

AcWing - 338 - 计数问题 = 数位dp

本秂侑毒 提交于 2019-11-30 16:05:36
https://www.acwing.com/problem/content/description/340/ 第一次做这种数数字的个数的,感觉理论上是差不多的,返回的不是1而是他的贡献罢了。 按道理要注意0的,但是题目里没有0。0毕竟是很特殊的,他全是前导0但也会贡献1个0。 #include<bits/stdc++.h> using namespace std; typedef long long ll; int a[40]; ll dp[10][40][40]; ll dfs(int id, int pos, int s1, bool lead, bool limit) { if(pos == -1) { return s1; } if(!limit && !lead && dp[id][pos][s1] != -1) return dp[id][pos][s1]; int up = limit ? a[pos] : 9; ll ans = 0; for(int i = 0; i <= up; i++) { int ns1 = s1 + (i == id); if(id == 0) ns1 = s1 + ((i == id) && (!lead)); ans += dfs(id, pos - 1, ns1, lead && i == 0, limit && i == a