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

http://wenku.baidu.com/view/d2414ffe04a1b0717fd5dda8.html

几位大大的数位BLOG:http://www.cnblogs.com/jackge/archive/2013/05/15/3080958.html

http://www.cnblogs.com/kuangbin/category/476047.html

CXLOVE:http://blog.csdn.net/acm_cxlove/article/details/7819907

给出数位DP的DFS记忆化DP模板;

因为原理比较简单,不用去构造方程,而且简洁。。

ll dfs(int pos,int cet,int sum,int flag){
   if (sum<) return ;
   if (pos<=) return sum==;
   if (!flag&&dp[pos][cet][sum]!=-) return dp[pos][cet][sum];
       int end=flag?a[pos]:;
   ll ret=;
   for (int i=;i<=end;i++)
   ret+=dfs(pos-,cet,sum+i*(pos-cet),flag&&(end==i));
   if (!flag) dp[pos][cet][sum]=ret;
   return ret;

}

复杂度是DP方程的状态数,DP设计的好坏与DP的状态数有关。。

FLAG表示是否在边界,当不再边界时我们可以做无关后面数的操作,否则,要考虑后面的数对前面有没有影响。。

我做的几道题:

HDU 3652:

 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
using namespace std;
int a[];
int len;
int dp[][][][]; int dfs(int pos,int sum,int res,int last,int flag)
{
if (pos<) return res&&(sum==);
if (!flag&&dp[pos][sum][res][last]!=-) return dp[pos][sum][res][last];
int end=flag?a[pos]:;
int ret=;
for (int i=;i<=end;i++)
ret+=dfs(pos-,(sum*+i)%,res||(last==&&i==),i,flag&&i==end);
if (!flag) dp[pos][sum][res][last]=ret;
return ret;
} int get(int x)
{
len=;
while (x){
a[len++]=x%;
x/=;
}
return dfs(len-,,,,);
} int main()
{
int n;
memset(dp,-,sizeof(dp));
while (scanf("%d",&n)!=EOF)
{
printf("%d\n",get(n));
}
}

HDU  3555:

 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
using namespace std;
typedef long long ll;
int a[];
int len;
ll dp[][][]; ll dfs(int pos,int res,int last,int flag)
{
if (pos<) return res;
if (!flag&&dp[pos][res][last]!=-) return dp[pos][res][last];
int end=flag?a[pos]:;
ll ret=;
for (int i=;i<=end;i++)
ret+=dfs(pos-,res||(last==&&i==),i,flag&&i==end);
if (!flag) dp[pos][res][last]=ret;
return ret;
} ll get(ll x)
{
len=;
while (x){
a[len++]=x%;
x/=;
}
return dfs(len-,,,);
} int main()
{
ll n;
int T;
scanf("%d",&T);
memset(dp,-,sizeof(dp));
while (T--)
{
scanf("%I64d",&n);
printf("%I64d\n",get(n));
}
}

HDU 4389:有打表方法;每个100000个数打表,再统计;

数位DP代码:

 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
typedef long long ll;
#define mod 2520
int inx[];
ll dp[][][];
int a[];
using namespace std; void init(){
int num=;
for (int i=;i<=mod;i++)
if (mod%i==) inx[i]=++num;
} int gcd(int a,int b){
if (a%b==) return b;
return gcd(b,a%b);
} int lcm(int a,int b){
return a*b/gcd(a,b);
} ll dfs(int pos,int slcm,int sum,int flag){
if (pos<) return sum%slcm==;
if (!flag&&dp[pos][inx[slcm]][sum]!=-) return dp[pos][inx[slcm]][sum];
int end=flag?a[pos]:;
ll ret=;
for (int i=;i<=end;i++){
int nowlcm=slcm;
int nowsum=(sum*+i) %mod;
if (i) nowlcm=lcm(nowlcm,i);
ret+=dfs(pos-,nowlcm,nowsum,flag&&i==end);
}
if (!flag) dp[pos][inx[slcm]][sum]=ret;
return ret;
} ll get(ll x)
{
int pos=;
while (x)
{
a[pos++]=x%;
x/=;
}
return dfs(pos-,,,);
} int main(){
int T;
scanf("%d",&T);
memset(dp,-,sizeof(dp));
init();
while (T--){
ll a,b;
scanf("%I64d%I64d",&a,&b);
printf("%I64d\n",get(b)-get(a-));
}
return ;
}

这里我们不可能保存每个值去除以其数位的和,我们可以枚举数位的和,然后DFS能满足的数的个数,再看其数能不能整除其数位。

数位和的状态是1-81。。。;

HDU 4334 :

 #include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<algorithm> using namespace std;
int bit[];
int dp[][]; int dfs(int t,int num,int flag)
{
if (t==) return num>=;
if (num<) return ;
if (!flag&&dp[num][t]!=-) return dp[num][t];
int ans=;
int end=flag?bit[t]:;
for (int i=;i<=end;i++)
ans+=dfs(t-,num-i*(<<(t-)),flag&&i==end);
if (!flag) dp[num][t]=ans;
return ans;
}
int main()
{
int T;
scanf("%d",&T);
memset(dp,-,sizeof(dp));
for (int i=;i<=T;i++)
{
int a,b;
scanf("%d%d",&a,&b);
int t=;
int ans=;
while (a)
{
ans+=a%*(<<t);
t++;
a/=;
}
int len=;
while (b)
{
bit[++len]=b%;
b/=;
}
printf("Case #%d: %d\n",i,dfs(len,ans,));
}
return ;
}

前面的做了差不多,这也是简单题了,先预处理F[A],然后处理。。

codeforces 55D: http://codeforces.com/problemset/problem/55/D

比较麻烦的题;求一个范围的书能被其数位整除的个数。

切题点:1-9的公倍数为2520;

我们可以定义方程DP[POS][LCM][SUM]表示:处理第POS位,其数位的最小公倍数数多少,该数MOD2520是多少,但是有个问题会爆内存,

要开DP[20][2520][2520];

解决办法是:2520=2^3*3^2*5*7

y于是又4*3*2*2= 48中组合。。

我们可以对LCM用下标代替,就不会爆内存了。。。真是奇妙的方法。。

 #include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
typedef long long ll;
#define mod 2520
int inx[];
ll dp[][][];
int a[];
using namespace std; void init(){
int num=;
for (int i=;i<=mod;i++)
if (mod%i==) inx[i]=++num;
} int gcd(int a,int b){
if (a%b==) return b;
return gcd(b,a%b);
} int lcm(int a,int b){
return a*b/gcd(a,b);
} ll dfs(int pos,int slcm,int sum,int flag){
if (pos<) return sum%slcm==;
if (!flag&&dp[pos][inx[slcm]][sum]!=-) return dp[pos][inx[slcm]][sum];
int end=flag?a[pos]:;
ll ret=;
for (int i=;i<=end;i++){
int nowlcm=slcm;
int nowsum=(sum*+i) %mod;
if (i) nowlcm=lcm(nowlcm,i);
ret+=dfs(pos-,nowlcm,nowsum,flag&&i==end);
}
if (!flag) dp[pos][inx[slcm]][sum]=ret;
return ret;
} ll get(ll x)
{
int pos=;
while (x)
{
a[pos++]=x%;
x/=;
}
return dfs(pos-,,,);
} int main(){
int T;
scanf("%d",&T);
memset(dp,-,sizeof(dp));
init();
while (T--){
ll a,b;
scanf("%I64d%I64d",&a,&b);
printf("%I64d\n",get(b)-get(a-));
}
return ;
}

FZU 2113:

OJ挂了,现在也没评测出来。。

求一个范围[L,R]数中1的总数。。

方程想到就是超级大水题;

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<cmath>
typedef long long ll;
int a[];
ll dp[][];
using namespace std; ll dfs(int pos,int num,int flag)
{
if (pos<) return num;
if (!flag&&dp[pos][num]!=-) return dp[pos][num];
int end=flag?a[pos]:;
ll ret=;
for (int i=;i<=end;i++)
if (i==) ret+=dfs(pos-,num+,flag&&end==i);
else ret+=dfs(pos-,num,flag&&end==i);
if (!flag) dp[pos][num]=ret;
return ret;
} ll get(ll x)
{
int pos=;
while (x){
a[pos++]=x%;
x/=;
}
return dfs(pos,,);
} int main()
{
ll a,b;
memset(dp,-,sizeof(dp));
while (scanf("%lld%lld",&a,&b)!=EOF){
printf("%lld\n",get(b)-get(a-));
}
return ;
}

还有好多好多各种状态的数位DP题,果然太弱切不动。。

数位DP之小小结的更多相关文章

  1. 数位DP复习小结

    转载请注明原文地址http://www.cnblogs.com/LadyLex/p/8490222.html 之前学数位dp的时候底子没打扎实 虚的要死 这次正好有时间……刷了刷之前没做的题目 感觉自 ...

  2. hdu 3709 数字dp(小思)

    http://acm.hdu.edu.cn/showproblem.php?pid=3709 Problem Description A balanced number is a non-negati ...

  3. 牛客寒假算法基础集训营3处女座和小姐姐(三) (数位dp)

    链接:https://ac.nowcoder.com/acm/contest/329/G来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言52428 ...

  4. 处女座和小姐姐(三)(数位dp)

    链接:https://ac.nowcoder.com/acm/contest/329/G 来源:牛客网 题目描述 经过了选号和漫长的等待,处女座终于拿到了给小姐姐定制的手环,小姐姐看到以后直呼666! ...

  5. [bzoj3209][花神的数论题] (数位dp+费马小定理)

    Description 背景众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦.描述话说花神这天又来讲课了.课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了. ...

  6. P2188 小Z的 k 紧凑数 题解(数位DP)

    题目链接 小Z的 k 紧凑数 解题思路 数位DP,把每一个数位的每一个数对应的可能性表示出来,然后求\(num(1,r)-num(1,l-1)\),其中\(num(i,j)\)表示\([i,j]\)区 ...

  7. 数位dp小练

    最近刷题的同时还得填填坑,说来你们也不信,我还不会数位dp. 照例推几篇博客: 数位DP讲解 数位dp 的简单入门 这两篇博客讲的都很好,不过代码推荐记搜的形式,不仅易于理解,还短. 数位dp的式子一 ...

  8. 数位dp小结

    数位dp其实就是一种用来求区间[l, r]满足条件的数的个数.数位是指:个十百千万,而在这里的dp其实相当于暴力枚举每一位数. 我们通过把l, r的每位数分解出来,然后分别求r里满足条件的数有多少,l ...

  9. 牛客训练三:处女座和小姐姐(三)(数位dp)

    题目链接:传送门 思路:数位dp的记忆化搜索模板 从高位向低位枚举,逐位确定每一位的6的个数,dp[i][s]表示处理到第i条边,状态为s时的数字的个数. 注意,要使用long long类型. #in ...

随机推荐

  1. 开源web终端ssh解决方案-gateone简介

    好久都没来写博客,最近忙啥去了呢? 一是忙于saltstack的二次开发,二是云计算的学习研究中,所以就一直没写东西,今天给大家介绍个工具. 1. 首先来说一下为什么要 web ssh? 许多人不是说 ...

  2. Wordpress模板标签大全

    Wordpress模板基本文件 style.css 样式表文件 index.php 主页文件 single.php 日志单页文件 page.php 页面文件 archvie.php 分类和日期存档页文 ...

  3. 小白学jquery Mobile《构建跨平台APP:jQuery Mobile移动应用实战》连载四(场景切换)

    作为一款真正有使用价值的应用,首先应该至少有两个页面,通过页面的切换来实现更多的交互.比如手机人人网,打开以后先是进入登录页面,登录后会有新鲜事,然后拉开左边的面板,能看到相册.悄悄话.应用之类的其他 ...

  4. Zygote(app_process)相关分析2

    在前一篇文章中已经分析了从init.c到Zygote(app_process)的启动流程. 今天开始分析frameworks/base/cmds/app_process/app_main.cpp. s ...

  5. 代码编译方式 ant +ivy

    Apache Ant,是一个将软件编译.测试.部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发.由Apache软件基金会所提供. 没用过ant,了解一下,无非就这些功能, 编 ...

  6. Swift Tips - 在 Swift 中自定义下标访问

    Untitled Document.md input[type="date"].form-control,.input-group-sm>input[type="d ...

  7. 条款38:通过聚合设计has-a或者is-implemented-in-terms-of

    聚合:类型之间的一种关系,就是一种类型内含有另一种类型的变量. has-a: class Address { }; class PhoneNumber { }; class Person { publ ...

  8. C#取枚举描述

    一直都觉得枚举是个很不错的东西,可以给我们带来很多方便,而且也增加代码的可读性. 我在之前已经介绍过枚举的简要应用了,再次再来写下怎么获取枚举的描述. 源码如下: 首先,我们定义个含有描述的枚举类型 ...

  9. [小技巧]让你的GridView支持IQueryable,并自动实现真分页

    众所周知,asp.net自带的GridView在自带分页方面设计得很2,因为它是假分页,即内存分页.而且它不智能支持强大的Iqueryable. 但这表明微软忽略了现实中的分页需求吗?答案应该不是,我 ...

  10. C++ 学习笔记(一)

    只是记录自己学习C++ 笔记实例来自<c++ primer> 1.static: static 局部对象确保不迟于在程序执行流程第一次经过该对象的定义语句时进行初始化.这种对象一旦被创建, ...