数位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 ...
随机推荐
- ElasticSearch.js
ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elasticsearch是用Java开发的,并作为Apach ...
- C# 平时碰见的问题【3】
今天发现一个问题纳闷了半个小时, 需求是处理project文件里边的数据内容,其中需要判断任务名称不存在重复; 在测试的时候弄了两行一样的任务,如预想: 任务[xxx]重复 然后删掉重复的任务行,继续 ...
- ARM-Linux S5PV210 UART驱动(3)----串口核心层、关键结构体、接口关系
尽管一个特定的UART设备驱动完全可以按照tty驱动的设计方法来设计,即定义tty_driver并实现tty_operations其中的成员函数,但是Linux已经在文件serial_core.c中实 ...
- Python脚本控制的WebDriver 常用操作 <十二> send_keys模拟按键输入
下面将使用WebDriver中的send_keys来模拟键盘按键输入 测试用例场景 send_keys方法可以模拟一些组合键操作: ctrl+a ctrl+c ctrl+v 等. 另外有时候我们需要在 ...
- iphone/ipad关于size, frame and bounds总结和UIScroll view学习笔记
1. iphone/ipad大小 Device Screen dimensions(in points) iphone and ipod 320 X 480 ipad 768 X 1024 2. UI ...
- Ubuntu下部署java JDK和eclipse IDE
安装Java编程开发环境: Ubuntu默认安装openjava,可以通过java -version查看是否安装.但我使用Ubuntu9.10升级到10.04LTS时,openjava没有了.另外,如 ...
- hdu 2648 Shopping
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=2648 纯暴力的方法T_T... 如下: #include<cstdio> #include ...
- android几种定时器机制及区别
在android中,经常用到的定时器主要有以下几种实现:一.采用Handler与线程的sleep(long )方法二.采用Handler的postDelayed(Runnable, long) 方法三 ...
- BASE64与单向加密算法MD5&SHA&MAC
言归正传,这里我们主要描述Java已经实现的一些加密解密算法,最后介绍数字证书. 如基本的单向加密算法: BASE64 严格地说,属于编码格式,而非加密算法 MD5(Message Diges ...
- ASP.NET浏览器定义文件及IE兼容模式
由于ASP.NET4.0中的一个小bug,导致了ASP.NET WebForms控制的CallBack无效,部分控件无法使用. 解决方法是在项目中添加自定义的浏览器定义文件,参考这里:http://w ...