题集见大佬博客

不要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. Kids Store - OpenCart 自适应主题模板 ABC-0022

    KIDS STORE - OPENCART 自适应主题模板 ABC-0022 FEATURES Get FREE Lifetime Updates Get FREE On-Going Support ...

  2. 请求文件下载URL过长处理

    /* * PostNewWin * Author:ppchen */var PostNewWin = function(url){    var urlArr = url.split("?& ...

  3. Ambarella SDK build 步骤解析

    Make Target Options make命令如下: make <Tab> <Tab> /*列出所有支持的目标(命令行输入make, 再按两下Tab键)*/ make & ...

  4. curses-键盘编码-openssl加解密【转】

    本文转载自;https://zhuanlan.zhihu.com/p/26164115 1.1 键盘编码 按键过程:当用户按下某个键时, 1.键盘会检测到这个动作,并通过键盘控制器把扫描码(scan ...

  5. hdu 1035(DFS)

    Robot Motion Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  6. Codeforces--615B--Longtail Hedgehog(贪心模拟)

     B. Longtail Hedgehog time limit per test 3 seconds memory limit per test 256 megabytes input stan ...

  7. Labeling Balls(拓扑)

    http://poj.org/problem?id=3687 看题意看了半天没看懂怎么回事,看完Discuss彻底凌乱了..后来看了题解才懂,就是逆向建图+拓扑排序,建图时要判重边. #include ...

  8. 8.19noip模拟题

      2017 8.19 NOIP模拟赛 by coolyangzc 共3道题目,时间3小时 题目名 高级打字机 不等数列 经营与开发 源文件 type.cpp/c/pas num.cpp/c/pas ...

  9. Redis(二)-Win系统下安装

    下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这个需要根据你系统平台的实际情况选择,这里我们下载 Red ...

  10. A - Design Tutorial: Learn from Math(哥德巴赫猜想)

    Problem description One way to create a task is to learn from math. You can generate some random mat ...