博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hdu4734 数位dp + 小技巧
阅读量:5310 次
发布时间:2019-06-14

本文共 2933 字,大约阅读时间需要 9 分钟。

题意:假设x的10进制数每一位分别为(AnAn-1An-2 ... A2A1),定义  F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1,求1-b中F(x)<=F(a)的数有多少个

思路:其实F(x)只是给每一个数位带上一个权值v=2^(p-1),F(x)最大是值不会超过5000,我们完全可以抛开权值来思考,写代码的时候再加上权值即可,这样思考和写草稿之类的会方便很多,不考虑每一位的权值的话即是数位的前缀和,

很容易想到一个dp式是dp[pos][sum];表示当前在第pos位,前缀和为sum的答案,快速把数位dp拍完,交上去,然后会发现T掉了,这题的时限只有500ms,T的原因是什么呢,就是记忆化不够彻底,在做数位dp入门题 不要62 的时候可能有点人会注意,dp数组只需要初始化一次即可,这是因为不要62题意中是不包含4和连续的62的数的个数,这里的条件是一个数本身的性质,也就是说,一个数有没有4或者连续的62和你输入的l r区间是无关的,比如1234是不合法的,无论你输入1 - 1000 还是 1 - 10000,1234都是不合法的,但是这里是不一样的,题意要求小于F(a),而a是输入的,而dp数组定义是:dp[pos][sum],表示当前在第pos位,前缀和为sum的答案, 如假设上限是55555, 那么123xxx 和 321xxx 的答案都是 dp[3][6] ,这就是记忆化的结果,因为我不需要考虑前面具体的数的123 还是321 114之类的,只要他们的前缀和sum相同并且在同样的数位,后面xxx的情况都是一样的,因为后面的约束条件都是和不大于F(a)-sum,问题就是在这个地方,由于我的记忆话是和输入的a也就是F(a)有关,所以我不能把它当作一个数的性质来记忆话,比如同样是123xxx,对于F(a)=10和F(a)=20,后面xxx可行的情况是不一样的,a=10的时候,后面的约束是不大于F(a)-sum=4,a=20的时候约束为不大于F(a)-sum=14,从而导致了每次输入不同的a都要重新初始化dp数组,从新搜索一次。这里可以通过队dp式的定义做一点小小的改变,使得约束条件变为与F(a)无关,从而不需要每次初始化重新搜索,定义dp[pos][sum],表示当前在第pos位,F(a)-sum的答案(sum为到第pos位为止的数位前缀和),这时在第pos位的约束条件是后面所有的数的和不大于sum,这时记忆化的是sum,是与F(a)无关的,比如当F(a)=10和F(a)=20时,F(a)=10时,123xxx、321xxx等对应的是dp[3][4], F(a)=20时,556xxx、466xxx对应的也是dp[3][4],因为2种情况的pos和F(a)-sum都是相同的,所以记忆化一次即可,不必初始化

AC代码:

#include "iostream"#include "iomanip"#include "string.h"#include "stack"#include "queue"#include "string"#include "vector"#include "set"#include "map"#include "algorithm"#include "stdio.h"#include "math.h"#pragma comment(linker, "/STACK:102400000,102400000")#define bug(x) cout<
<<" "<<"UUUUU"<
fa) return 0; if(!limit && dp[pos][fa-sum]!=-1) return dp[pos][fa-sum]; int up=limit?bit[pos]:9, ans=0; for(int i=0; i<=up; ++i){ ans+=dfs(limit&&i==bit[pos], sum+i*(1<<(pos)), pos-1); } if(!limit) dp[pos][fa-sum]=ans; return ans;}int solve(int s, int x){ int t=0,k=1; fa=0; while(x>0){ bit[t++]=x%10; x/=10; } while(s>0){ fa+=(s%10)*k; s/=10, k*=2; } return dfs(1,0,t-1);}int main(){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); mem(dp,-1); int T,cas=0; cin>>T; while(T--){ cin>>a>>b; cout<<"Case #"<<++cas<<": "; cout<
<

再贴T的代码:

#include "bits/stdc++.h"using namespace std;int fa,bit[25],dp[25][10000];int dfs(int limit, int pos, int sum){    if(pos==-1) return sum<=fa;    if(sum>fa) return 0;    if(!limit && dp[pos][sum]!=-1) return dp[pos][sum];    int up=limit?bit[pos]:9, ans=0;    for(int i=0; i<=up; ++i){        ans+=dfs(limit&&i==bit[pos], pos-1, sum+i*(1<
0){ fa+=a%10*k; a/=10, k<<=1; } while(b>0){ bit[p++]=b%10; b/=10; } return dfs(1,p-1,0);}int main(){ int a,b,T,cas=0; memset(dp,-1,sizeof(dp)); scanf("%d",&T); while(T--){ scanf("%d%d",&a,&b); printf("Case #%d: %d\n",++cas,solve(a,b)); } return 0;}

 

转载于:https://www.cnblogs.com/max88888888/p/7577208.html

你可能感兴趣的文章
VMware中CentOS设置静态IP
查看>>
[poj1006]Biorhythms
查看>>
jsp
查看>>
Hyper-V虚拟机上安装一个图形界面的Linux系统
查看>>
Hover功能
查看>>
js千分位处理
查看>>
Mac---------三指拖移
查看>>
关于VMare中安装Ubuntu的一些说明
查看>>
字符串类型的相互转换
查看>>
HTTP状态码
查看>>
iOS如何过滤掉文本中特殊字符
查看>>
python - wmi模块学习(windwos硬件信息获取)
查看>>
Maven------使用maven新建web项目出现问题 项目名称出现红色交叉
查看>>
基础学习:C#中float的取值范围和精度
查看>>
Akka-Cluster(3)- ClusterClient, 集群客户端
查看>>
MongoDB-CRUD
查看>>
javaagent 简介
查看>>
python升级安装后的yum的修复
查看>>
Vim配置Node.js开发工具
查看>>
web前端面试题2017
查看>>