题集见大佬博客

不要62

入门题,检验刚才自己有没有看懂

注意一些细节。

的确挺套路的

#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; const int MAXN = ;
int a[MAXN], dp[MAXN][MAXN][MAXN], len; //dp数组记录除了lead和limit以外其他的东西 int dfs(int pos, int pre, int lead, int sum, int limit)
{
if(pos > len) return sum;
if(dp[pos][pre][sum] != - && !limit && !lead) return dp[pos][pre][sum]; //记忆化的时候记得limit和lead
int l = limit ? a[len-pos+] : , res = ; //注意是倒序存的,所以是len-pos+1
_for(i, , l)
{
if(!i && lead) res += dfs(pos + , pre, lead, sum, limit && (i == l)); //先看是不是前导0
else if(i && lead) res += dfs(pos + , i, , sum | (i == ), limit && (i == l)); //看是不是第一位
else res += dfs(pos + , i, , sum | (i == ) | (pre == && i == ), limit && (i == l)); //正式处理
}
return (!limit && !lead) ? dp[pos][pre][sum] = res : res; //记忆化的时候记得limit和lead
} int part(int x)
{
if(x < ) return ; //0的处理
memset(dp, -, sizeof(dp));
len = ; int t = x;
for(; x; x /= ) a[++len] = x % ;
return t - dfs(, , , , );
} int main()
{
int n, m;
while(scanf("%d%d", &n, &m))
{
if(n == && m == ) break;
printf("%d\n", part(m) - part(n - ));
}
return ;
}

P2657 [SCOI2009]windy数

继续套路

#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; const int MAXN = ;
int a[MAXN], dp[MAXN][MAXN][MAXN], len; int dfs(int pos, int pre, int ans, int lead, int limit)
{
if(pos > len) return ans;
if(dp[pos][pre][ans] != - && (!limit && !lead)) return dp[pos][pre][ans];
int l = limit ? a[len-pos+] : , res = ;
_for(i, , l)
{
if(!i && lead) res += dfs(pos + , pre, ans, lead, limit & (i == l));
else if(i && lead) res += dfs(pos + , i, ans, , limit & (i == l));
else res += dfs(pos + , i, ans & (abs(i - pre) >= ), , limit & (i == l));
}
return (!limit && !lead) ? dp[pos][pre][ans] = res : res;
} int part(int x)
{
if(x == ) return ;
memset(dp, -, sizeof(dp));
len = ;
for(; x; x /= ) a[++len] = x % ;
return dfs(, , , , );
} int main()
{
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", part(b) - part(a - ));
return ;
}

P2602 [ZJOI2010]数字计数

第一次这么轻松做出紫题

一样套模板,爽啊

#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; typedef long long ll;
const int MAXN = ;
const int MAXM = 1e6 + ;
ll dp[MAXN][MAXN];
int a[MAXN], len; ll dfs(int pos, int ans, int lead, int limit, int key)
{
if(pos > len) return ans;
if(dp[pos][ans] != - && (!lead && !limit)) return dp[pos][ans];
int l = limit ? a[len-pos+] : ; ll res = ;
_for(i, , l)
{
if(!i && lead) res += dfs(pos + , ans, lead, limit && (i == l), key);
else res += dfs(pos + , ans + (i == key), , limit && (i == l), key);
}
return (!lead && !limit) ? dp[pos][ans] = res : res;
} ll part(ll x, int i)
{
memset(dp, -, sizeof(dp));
len = ;
for(; x > ; x /= ) a[++len] = x % ;
return dfs(, , , , i);
} inline ll work(ll a, ll b, int i)
{
return a ? part(b, i) - part(a - , i) : part(b, i) - part(a, i) + (i == );
} int main()
{
ll a, b;
scanf("%lld%lld", &a, &b);
_for(i, , )
printf("%lld%c", work(a, b, i), i == ? '\n' : ' ');
return ;
}

P3413 SAC#1 - 萌数

注意数字很大,要用字符串存储

然后就没啥了,又独立做出紫题

#include<bits/stdc++.h>
#define add(a, b) a = (a + b) % mod
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; const int MAXN = ;
const int MAXM = 1e3 + ;
const int mod = 1e9 + ; int dp[MAXM][MAXN][MAXN][];
int a[MAXM], len;
char s1[MAXM], s2[MAXM]; int dfs(int pos, int pre, int ppre, int ans, int lead, int limit)
{
if(pos > len) return ans;
if(dp[pos][pre][ppre][ans] != - && (!lead && !limit)) return dp[pos][pre][ppre][ans];
int l = limit ? a[len-pos+] : ; int res = ;
_for(i, , l)
{
if(!i && lead) add(res, dfs(pos + , pre, ppre, ans, lead, limit && (i == l)));
else if(i && lead) add(res, dfs(pos + , i, pre, ans, , limit && (i == l)));
else add(res, dfs(pos + , i, pre, ans | (i == pre) | (i == ppre), , limit && (i == l)));
}
return (!lead && !limit) ? dp[pos][pre][ppre][ans] = res : res;
} int part(char* s)
{
memset(dp, -, sizeof(dp));
len = strlen(s + );
_for(i, , len) a[i] = s[len - i + ] - '';
return dfs(, -, -, , , );
} int judge(char* s)
{
_for(i, , strlen(s + ))
if(s[i] == s[i-] || s[i] == s[i-])
return ;
return ;
} int main()
{
scanf("%s%s", s1 + , s2 + );
if(s1[] == && strlen(s1 + ) == ) printf("%d\n", (part(s2) - part(s1) + mod) % mod);
else printf("%d\n", (part(s2) - part(s1) + mod + judge(s1)) % mod);
return ;
}

P4127 [AHOI2009]同类分布

一开始想的时候当前的数肯定是不能记到答案里的

当然如果知道模数,一直取模就可以限制范围,就很好了

但问题是我们并不知道模数,这就比较尴尬了

就一直卡在这

然而正解非常暴力,但却是对的。

既然不知道模数,那就枚举模数

最后判断一下数字和是不是当前模数且能否整除就好了。

我为什么没想到呢?

注意数位dp要开long long

#include<bits/stdc++.h>
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; typedef long long ll;
const int MAXN = ;
ll dp[MAXN][MAXN*][MAXN*];
int a[MAXN], len, mod; ll dfs(int pos, int num, int state, int lead, int limit)
{
if(pos > len) return num == mod && state == ;
if(dp[pos][num][state] != - && (!lead && !limit)) return dp[pos][num][state];
int l = limit ? a[len-pos+] : ; ll res = ;
_for(i, , l)
{
if(!i && lead) res += dfs(pos + , num, state, lead, limit && (i == l));
else if(i && lead) res += dfs(pos + , i, i % mod, , limit && (i == l));
else res += dfs(pos + , num + i, (state * + i) % mod, , limit && (i == l));
}
return (!lead && !limit) ? dp[pos][num][state] = res : res;
} ll part(ll x)
{
len = ;
for(; x; x /= ) a[++len] = x % ;
ll res = ;
for(mod = ; mod <= len * ; mod++)
{
memset(dp, -, sizeof(dp));
res += dfs(, , , , );
}
return res;
} int main()
{
ll a, b;
scanf("%lld%lld", &a, &b);
printf("%lld\n", !a ? part(b) - part(a) : part(b) - part(a - ));
return ;
}

P4317 花神的数论题

用二进制统计就好了

不过很奇怪的是一开始我数组开的大小是50

因为用程序输出1e15最多的位数是47

但是交上去会WA一个点

改成51就过了

以后只要空间剩余多,就多开一些吧,程序中有些神奇的地方可能会比理论上最大值超出一些

#include<bits/stdc++.h>
#define mul(a, b) a = (a * b) % mod
#define REP(i, a, b) for(register int i = (a); i < (b); i++)
#define _for(i, a, b) for(register int i = (a); i <= (b); i++)
using namespace std; typedef long long ll;
const int MAXN = ;
const int mod = ;
ll dp[MAXN][MAXN];
int a[MAXN], len; ll dfs(int pos, int ans, int lead, int limit)
{
if(pos > len) return max(, ans);
if(dp[pos][ans] != - && (!limit && !lead)) return dp[pos][ans];
int l = limit ? a[len-pos+] : ; ll res = ;
_for(i, , l)
{
if(!i && lead) mul(res, dfs(pos + , ans, lead, limit && (i == l)));
else mul(res, dfs(pos + , ans + i, , limit && (i == l)));
}
return (!limit && !lead) ? dp[pos][ans] = res : res;
} ll part(ll x)
{
len = ;
for(; x; x >>= ) a[++len] = x & ;
memset(dp, -, sizeof(dp));
return dfs(, , , );
} int main()
{
ll a;
scanf("%lld", &a);
printf("%lld\n", part(a));
return ;
}

总结

感觉都是套路,掌握套路就好了

相信自己已经掌握了数位dp

数位dp题集的更多相关文章

  1. (计数器)NOIP模拟赛(神奇的数位DP题。。)

    没有原题传送门.. 手打原题QAQ [问题描述]     一本书的页数为N,页码从1开始编起,请你求出全部页码中,用了多少个0,1,2,…,9.其中—个页码不含多余的0,如N=1234时第5页不是00 ...

  2. 杭电dp题集,附链接还有解题报告!!!!!

    Robberies 点击打开链接 背包;第一次做的时候把概率当做背包(放大100000倍化为整数):在此范围内最多能抢多少钱  最脑残的是把总的概率以为是抢N家银行的概率之和- 把状态转移方程写成了f ...

  3. DP 题集 2

    关于 DP 的一些题目 String painter 先区间 DP,\(dp[l][r]\) 表示把一个空串涂成 \(t[l,r]\) 这个子串的最小花费.再考虑 \(s\) 字符串,\(f[i]\) ...

  4. DP 题集 1

    关于 DP 的一些题目 参考资料 [Tutorial] Non-trivial DP Tricks and Techniques DP Rain and Umbrellas Mr. Kitayuta, ...

  5. 浅谈数位DP

    在了解数位dp之前,先来看一个问题: 例1.求a~b中不包含49的数的个数. 0 < a.b < 2*10^9 注意到n的数据范围非常大,暴力求解是不可能的,考虑dp,如果直接记录下数字, ...

  6. HDU 3709 Balanced Number (数位DP)

    Balanced Number Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) ...

  7. 数位DP之小小结

    资料链接:http://wenku.baidu.com/view/9de41d51168884868662d623.html http://wenku.baidu.com/view/d2414ffe0 ...

  8. HDU5787 K-wolf Number 数位dp

    分析:赛场上也知道是裸的数位dp,但是无奈刷数位dp题刷的太少了,并不能写出来 一点感想:赛后补题,看了题解的map记录状态,一脸蒙逼,也是非常的不爽,然后想看别人写的,不是递归就是写的比较乱 而且我 ...

  9. ural 1057(数位dp)

    数位dp题,关键是用树的思维去考虑. 对于一个数字X,要是能表示成K个B的不同次幂,等价于X在B进制下有且只有K个位上面的数字为一,其他位上的数字都为0. 具体读者可以去参考,国家集训队李聪的论文,里 ...

随机推荐

  1. 保护眼睛-eclipse黑色背景设置

    eclipse中java编辑器颜色改动,适合程序员人群: 长时间编码,眼睛是有非常大负担的,特别是使用eclipse,它自带的java编辑器背景色是刺眼的白色.代码颜色基本是黑色,这样一个编辑器里白色 ...

  2. 自己定义控件-仿iphone之ToggleButton&amp;VoiceSeekBar

    由于项目中须要使用开关切换button,和声音滑动控件,可是原生Android5.0版本号以下的控件实在是太挫了.尽管网上已经有非常多关于这两个控件的blog.可是我实在是找不到像iPhone这样简洁 ...

  3. luogu1373 小a和uim之大逃离

    题目大意 地面上出现了一个n*m的巨幅矩阵,矩阵的每个格子上有一坨0~k不等量的魔液.怪物各给了小a和uim一个魔瓶,说道,你们可以从矩阵的任一个格子开始,每次向右或向下走一步,从任一个格子结束.开始 ...

  4. git出错调试

    https://stackoverflow.com/questions/6178401/how-can-i-debug-git-git-shell-related-problems git_trace ...

  5. bzoj3110 [Zjoi2013]K大数查询——线段树套线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3110 外层权值线段树套内层区间线段树: 之所以外层权值内层区间,是因为区间线段树需要标记下传 ...

  6. 杂项-Java:JDBC

    ylbtech-杂项-Java:JDBC JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访 ...

  7. 444D

    分类 首先我们要对询问分类,如果相差log级别就第一种询问,否则第二种. 第一种直接暴力lower_bound,复杂度玄学 第二种归并,复杂度玄学 但是就是过了.感觉很容易卡. #include< ...

  8. JavaScript学习三

    2019-05-30 20:38:50 逻辑运算符 && || ! !如果对非布尔值取反,则将会把数值变成布尔值,然后再取反 隐式类型转化 为任意的数据类型做两次非运算,既可将其转换成 ...

  9. python 11:range(起始索引,终止索引,步数)(默认情况下步数为1,生成从起始索引,每次增加(终止索引-起始索引)/步数,到终止索引前的数字串)

    squares = [] for value in range(1,11): #第三参数默认为1,生成从1开始,每次增加1步数,到11前的10为止的数字串 square = value ** 2 sq ...

  10. Python-控制流

    if #!/usr/bin/python number=23 guess=int(input('Enter an interger:')) #input返回的结果是string类型,需要用int()转 ...