[HDU4734] F(x)(数位dp+优化)
>传送门<
题意:对于一个有n位(这n位从高位到低位分别是An,An-1,An-2 ... A2,A1)的十进制数,我们定义它的权值F(x)=An*2n-1 + An-1*2n-2 + ... + A2*2 + A1*1.现在给你两个数A,B,请计算[0,B]范围内有多少个权值<=F(A)的数
思路:(这个下面文字是有点多,可能是我太弱了,在刚开始学的时候只有这样我才能理解QAQ~)
其实F(x)只是给每一个数位带上一个权值v = 2^(p-1),F(x)最大是值不会超过5000,我们完全可以抛开权值来思考,写代码的时候再加上权值即可,这样思考和写草稿之类的会方便很多,不考虑每一位的权值的话即是数位的前缀和。
很容易想到一个dp式是dp[pos][sum];表示当前在第pos位,前缀和为sum的答案,快速把数位dp敲完,交上去,然后会发现TLE掉了,这题的时限只有500ms,TLE的原因是什么呢,就是记忆化不够彻底。
在做数位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都是相同的,所以记忆化一次即可,不必初始化
总结一下,在设计数位dp状态时最好把每次询问的变量作为初始值而不是状态转移、判定时依赖的量(比如第一个状态判定条件是F(x)<=F(a),就依赖于当前F(a),这样就不好),这样才可以最大限度的发挥记忆化的作用。
Code
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e4+5; int A, B, t, tot;
int a[12], dp[12][maxn];
int f(int x) {
int ans = 0, cnt = 0;
while(x){
ans += (x%10)*(1<<(cnt++));
x /= 10;
}
return ans;
}
int dfs(int pos, int sum, int limit) {
if(pos==0) return sum<=tot;
if(sum>tot) return 0;
if(!limit&&dp[pos][tot-sum]!=-1) return dp[pos][tot-sum];
int up = limit?a[pos]:9;
int ans = 0;
for(int i = 0; i <= up; i++)
ans += dfs(pos-1, sum+i*(1<<(pos-1)), limit&&i==a[pos]);
if(!limit) dp[pos][tot-sum] = ans;
return ans;
}
int solve(int x) {
int pos = 1;
while(x) {
a[pos++] = x%10;
x /= 10;
}
return dfs(pos-1, 0, 1);
}
int main()
{
int kase = 1;
memset(dp,-1,sizeof dp);
scanf("%d", &t);
while(t--) {
scanf("%d%d", &A, &B);
tot = f(A);
printf("Case #%d: %d\n", kase++, solve(B));
}
return 0;
}
参考文章:
https://www.cnblogs.com/AbandonZHANG/p/4114122.html
http://www.bubuko.com/infodetail-2320548.html
https://blog.csdn.net/wust_zzwh/article/details/52100392
https://www.cnblogs.com/herumw/p/9464514.html
[HDU4734] F(x)(数位dp+优化)的更多相关文章
- [hdu4734]F(x)数位dp
题意:求0~f(b)中,有几个小于等于 f(a)的. 解题关键:数位dp #include<bits/stdc++.h> using namespace std; typedef long ...
- hdu4734 F(x)(数位dp)
题目传送门 F(x) Time Limit: 1000/500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- HDU-4734 F(x) 数位DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734 注意到F(x)的值比较小,所以可以先预处理所有F(x)的组合个数.f[i][j]表示 i 位数时 ...
- 【hdu4734】F(x) 数位dp
题目描述 对于一个非负整数 $x=\overline{a_na_{n-1}...a_2a_1}$ ,设 $F(x)=a_n·2^{n-1}+a_{n-1}·2^{n-2}+...+a_2·2^1+ ...
- hdoj4734(数位dp优化)
题目链接:https://vjudge.net/problem/HDU-4734 题意:定义一个十进制数AnAn-1...A1的value为An*2n-1+...+A1*20,T组样例(<=1e ...
- hdu 4389 X mod f(x) 数位DP
思路: 每次枚举数字和也就是取模的f(x),这样方便计算. 其他就是基本的数位Dp了. 代码如下: #include<iostream> #include<stdio.h> # ...
- HDU 4734 F(x) ★(数位DP)
题意 一个整数 (AnAn-1An-2 ... A2A1), 定义 F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1,求[0..B]内有多少 ...
- hdu 4734 F(x)(数位dp+优化)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734 题意:我们定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2 ...
- HDU 4734 - F(x) - [数位DP][memset优化]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734 Time Limit: 1000/500 MS (Java/Others) Memory Lim ...
随机推荐
- 第12章 DOM操作
目录 *1. 向DOM中注入HTML 1.1 将HTNL字符串转换成DOM 预处理HTML源字符串 包装HTML 1.2 将DOM元素插入到文档中 2. DOM的特性和属性 通过DOM方法和属性访问特 ...
- [从源码学设计]蚂蚁金服SOFARegistry 之 ChangeNotifier
[从源码学设计]蚂蚁金服SOFARegistry 之 ChangeNotifier 目录 [从源码学设计]蚂蚁金服SOFARegistry 之 ChangeNotifier 0x00 摘要 0x01 ...
- 【Flutter】可滚动组件之SingleChildScrollView
前言 SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子组件. 接口描述 const SingleChildScrollView({ Key ke ...
- ubuntu环境下搭建Hadoop集群中必须需要注意的问题
博主安装的hadoop是3.1.3这里是按照厦门大学那个博客安装的,在安装与启动过程中,费了不少事,特此记录一下问题. 安装的连接: 安装环境:http://dblab.xmu.edu.cn/blog ...
- 7.prometheus之查询API
一.格式概述 二.表达式查询 2.1 Instant queries(即时查询) 2.2 范围查询 三.查询元数据 3.1 通过标签匹配器找到度量指标列表 3.2 获取标签名 3.3 查询标签值 四. ...
- Head First 设计模式 —— 14. 复合 (Compound) 模式
复合模式 在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题. P500 思考题 public interface Quackable { public void quack(); } p ...
- [翻译]Azure 网关迁移至 .NET Core 3.1 性能提升一倍
原文:[Azure Active Directory's gateway is on .NET Core 3.1!] Azure Active Directory 的网关服务是一个反向代理,它为构成 ...
- java中如何踢人下线?封禁某个账号后使其会话立即掉线!
需求场景 封禁账号是一个比较常见的业务需求,尤其是在论坛.社区类型的项目中,当出现了违规用户时我们需要将其账号立即封禁. 常规的设计思路是:在设计用户表时增加一个状态字段,例如:status,其值为1 ...
- D2Admin 登录用户重新初始话右侧菜单
背景 最近用到D2Admin开发项目,用户登录菜单要根据用户角色权限获取,但是又不想用官网的方案(vue基于d2-admin的RBAC权限管理解决方案),所以自己加了个只修改 menuAside的方案 ...
- MySQL全面瓦解19:游标相关
定义 我们经常会遇到这样的一种情况,需要对我们查询的结果进行遍历操作,并对遍历到的每一条数据进行处理,这时候就会使用到游标. 所以:游标(Cursor)是处理数据的一种存储在MySQL服务器上的数据库 ...