资料链接: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. CentOS7.0安装与配置Tomcat-7

    解决权限不够 #chmod a+x filename 安装说明 安装环境:CentOS-7.0.1406安装方式:源码安装 软件:apache-tomcat-7.0.29.tar.gz 下载地址:ht ...

  2. Mysql 简单问题汇总(持续更新)

    主从架构相关问题 问题现象:从机连接主机时报错 [ERROR] Slave I/O: error connecting to master 'repl@192.168.0.50:3306' - ret ...

  3. linuxok6410的I2C驱动分析---用户态驱动

    3  i2c-dev 3.1 概述 之前在介绍I2C子系统时,提到过使用i2c-dev.c文件在应用程序中实现我们的I2C从设备驱动.不过,它实现的是一个虚拟,临时的i2c_client,随着设备文件 ...

  4. mysql字段累加concat

    update tablename set field1=concat(field1,'_bak') where field2 like '%@xxx’

  5. Couchbase server---Enyim.Caching.dll

    本文不打算抄袭官方或者引用他人对Couchbase的各种描述,仅仅是自己对它的一点理解(错误之处,敬请指出),并附上一个入门示例. ASP.NET Web项目(其他web开发平台也一样)应用规模小的时 ...

  6. HTML QQ聊天代码 简单的一行代码

    简单的一行代码: <a href="tencent://message/?uin=173007740&Site=&Menu=yes">和17300774 ...

  7. 010--VS2013 C++ 平面地图贴图

    先准备好地图的小图片: //全局变量HDC mdc;HBITMAP fullmap;const int rows = 8, cols = 8; //-------------------------- ...

  8. FPGA控制HC595

    /*****************************************************************************Copyright: 2013File na ...

  9. java判断某个字符串包含某个字符串的个数

    /** * 判断str1中包含str2的个数 * @param str1 * @param str2 * @return counter */ public static int countStr(S ...

  10. React + Reflux

    React + Reflux 渲染性能优化原理   作者:ManfredHu 链接:http://www.manfredhu.com/2016/11/08/23-reactRenderingPrinc ...