数位DP之小小结
资料链接: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 ;
}
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之小小结的更多相关文章
- 数位DP复习小结
转载请注明原文地址http://www.cnblogs.com/LadyLex/p/8490222.html 之前学数位dp的时候底子没打扎实 虚的要死 这次正好有时间……刷了刷之前没做的题目 感觉自 ...
- hdu 3709 数字dp(小思)
http://acm.hdu.edu.cn/showproblem.php?pid=3709 Problem Description A balanced number is a non-negati ...
- 牛客寒假算法基础集训营3处女座和小姐姐(三) (数位dp)
链接:https://ac.nowcoder.com/acm/contest/329/G来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言52428 ...
- 处女座和小姐姐(三)(数位dp)
链接:https://ac.nowcoder.com/acm/contest/329/G 来源:牛客网 题目描述 经过了选号和漫长的等待,处女座终于拿到了给小姐姐定制的手环,小姐姐看到以后直呼666! ...
- [bzoj3209][花神的数论题] (数位dp+费马小定理)
Description 背景众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦.描述话说花神这天又来讲课了.课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了. ...
- P2188 小Z的 k 紧凑数 题解(数位DP)
题目链接 小Z的 k 紧凑数 解题思路 数位DP,把每一个数位的每一个数对应的可能性表示出来,然后求\(num(1,r)-num(1,l-1)\),其中\(num(i,j)\)表示\([i,j]\)区 ...
- 数位dp小练
最近刷题的同时还得填填坑,说来你们也不信,我还不会数位dp. 照例推几篇博客: 数位DP讲解 数位dp 的简单入门 这两篇博客讲的都很好,不过代码推荐记搜的形式,不仅易于理解,还短. 数位dp的式子一 ...
- 数位dp小结
数位dp其实就是一种用来求区间[l, r]满足条件的数的个数.数位是指:个十百千万,而在这里的dp其实相当于暴力枚举每一位数. 我们通过把l, r的每位数分解出来,然后分别求r里满足条件的数有多少,l ...
- 牛客训练三:处女座和小姐姐(三)(数位dp)
题目链接:传送门 思路:数位dp的记忆化搜索模板 从高位向低位枚举,逐位确定每一位的6的个数,dp[i][s]表示处理到第i条边,状态为s时的数字的个数. 注意,要使用long long类型. #in ...
随机推荐
- 获取枚举的title
public class StringValue : System.Attribute { private readonly string _value; public StringValue(str ...
- Java 第五天 Spring IOC 配置文件
Spring xml结构定义文件: http://www.springframework.org/schema/beans/spring-beans.xsd 可用xsd列表: http://www.s ...
- [terry笔记]IMPDP报错ORA-39083 Object type TYPE failed to create ORA-02304
今天在使用impdp导入的时候(同一数据库中转换schema),遇到了 ORA-39083: Object type TYPE failed to create with error: ORA-023 ...
- Python学习教程(learning Python)--2.3.4Python函数返回值
本节讨论Python函数返回值问题. Python和C语言一样,也可以在函数结束时返回一个值.但在定义自己的Python函数时,是不需要指定返回值数据类型的,这和Python不关心变量的数据类型是一致 ...
- TETRIS 项目开发笔记
java学习一个月了,没有什么进展,期间又是复习Linux,又是看Android,瞻前顾后,感觉自己真的是贪得无厌, 学习的东西广而不精,所以写出的文章也就只能泛泛而谈.五一小长假,哪里都没有去,也不 ...
- CDN技术原理
要了解CDN的实现原理,首先让我们来回顾一下网站传统的访问过程,以便理解其与CDN访问方式之间的差别: 由上图可见,传统的网站访问过程为: 1. 用户在浏览器中输入要访问的域名: 2. 浏览器向域名解 ...
- 自定义Drawable
本文由 伯乐在线 - treesouth 翻译,toolate 校稿.未经许可,禁止转载! 英文出处:ryanharter.com.欢迎加入翻译小组. 我们看过一些博客文章,讲述了为什么要适时地使用自 ...
- (转)android Fragments详解一:概述
Fragment是activity的界面中的一部分或一种行为.你可以把多个Fragment们组合到一个activity中来创建一个多面界面并且你可以在多个activity中重用一个Fragment.你 ...
- 如何使用和了解ALTERA的IP核
可以通过直接对IP核进行仿真验证,通过波形来分析IP核的功能和工作方式,以及各个寄存器之间的工作关系. 也可以通过查看用户指导手册来学习IP核,如下图.
- Linux Shell常用技巧(目录)
Linux Shell常用技巧(一) http://www.cnblogs.com/stephen-liu74/archive/2011/11/10/2240461.html一. 特殊文件: /dev ...