>传送门<
题意:对于一个有n位(这n位从高位到低位分别是AnAn-1An-2 ... A2A1)的十进制数,我们定义它的权值F(x)=An*2n-1 + An-1*2n-2 + ... + A2*2 + A1*1.现在给你两个数AB,请计算[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) = 10F(a) = 20,后面xxx可行的情况是不一样的,a=10的时候,后面的约束是不大于F(a)-sum = 4a = 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) = 10F(a) = 20时,F(a) = 10时,123xxx、321xxx等对应的是dp[3][4] F(a)=20时,556xxx、466xxx对应的也是dp[3][4],因为2种情况的posF(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+优化)的更多相关文章

  1. [hdu4734]F(x)数位dp

    题意:求0~f(b)中,有几个小于等于 f(a)的. 解题关键:数位dp #include<bits/stdc++.h> using namespace std; typedef long ...

  2. hdu4734 F(x)(数位dp)

    题目传送门 F(x) Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  3. HDU-4734 F(x) 数位DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734 注意到F(x)的值比较小,所以可以先预处理所有F(x)的组合个数.f[i][j]表示 i 位数时 ...

  4. 【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+ ...

  5. hdoj4734(数位dp优化)

    题目链接:https://vjudge.net/problem/HDU-4734 题意:定义一个十进制数AnAn-1...A1的value为An*2n-1+...+A1*20,T组样例(<=1e ...

  6. hdu 4389 X mod f(x) 数位DP

    思路: 每次枚举数字和也就是取模的f(x),这样方便计算. 其他就是基本的数位Dp了. 代码如下: #include<iostream> #include<stdio.h> # ...

  7. HDU 4734 F(x) ★(数位DP)

    题意 一个整数 (AnAn-1An-2 ... A2A1), 定义 F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1,求[0..B]内有多少 ...

  8. 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 ...

  9. HDU 4734 - F(x) - [数位DP][memset优化]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734 Time Limit: 1000/500 MS (Java/Others) Memory Lim ...

随机推荐

  1. 第12章 DOM操作

    目录 *1. 向DOM中注入HTML 1.1 将HTNL字符串转换成DOM 预处理HTML源字符串 包装HTML 1.2 将DOM元素插入到文档中 2. DOM的特性和属性 通过DOM方法和属性访问特 ...

  2. [从源码学设计]蚂蚁金服SOFARegistry 之 ChangeNotifier

    [从源码学设计]蚂蚁金服SOFARegistry 之 ChangeNotifier 目录 [从源码学设计]蚂蚁金服SOFARegistry 之 ChangeNotifier 0x00 摘要 0x01 ...

  3. 【Flutter】可滚动组件之SingleChildScrollView

    前言 SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子组件. 接口描述 const SingleChildScrollView({ Key ke ...

  4. ubuntu环境下搭建Hadoop集群中必须需要注意的问题

    博主安装的hadoop是3.1.3这里是按照厦门大学那个博客安装的,在安装与启动过程中,费了不少事,特此记录一下问题. 安装的连接: 安装环境:http://dblab.xmu.edu.cn/blog ...

  5. 7.prometheus之查询API

    一.格式概述 二.表达式查询 2.1 Instant queries(即时查询) 2.2 范围查询 三.查询元数据 3.1 通过标签匹配器找到度量指标列表 3.2 获取标签名 3.3 查询标签值 四. ...

  6. Head First 设计模式 —— 14. 复合 (Compound) 模式

    复合模式 在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题. P500 思考题 public interface Quackable { public void quack(); } p ...

  7. [翻译]Azure 网关迁移至 .NET Core 3.1 性能提升一倍

    原文:[Azure Active Directory's gateway is on .NET Core 3.1!] Azure Active Directory 的网关服务是一个反向代理,它为构成 ...

  8. java中如何踢人下线?封禁某个账号后使其会话立即掉线!

    需求场景 封禁账号是一个比较常见的业务需求,尤其是在论坛.社区类型的项目中,当出现了违规用户时我们需要将其账号立即封禁. 常规的设计思路是:在设计用户表时增加一个状态字段,例如:status,其值为1 ...

  9. D2Admin 登录用户重新初始话右侧菜单

    背景 最近用到D2Admin开发项目,用户登录菜单要根据用户角色权限获取,但是又不想用官网的方案(vue基于d2-admin的RBAC权限管理解决方案),所以自己加了个只修改 menuAside的方案 ...

  10. MySQL全面瓦解19:游标相关

    定义 我们经常会遇到这样的一种情况,需要对我们查询的结果进行遍历操作,并对遍历到的每一条数据进行处理,这时候就会使用到游标. 所以:游标(Cursor)是处理数据的一种存储在MySQL服务器上的数据库 ...