2021-07-08-F(x) HDU - 4734(数位DP+模板+总结1)

传送门

  1. 这个专题的前几篇博客熟悉了数位DP的形式。
  2. 现在慢慢来理解:
    2.1 关键是找到dp函数
    2.2 dfs-只需要注意边界操作和剪枝即可(dfs函数本身返回的值我们可以像dp一样把它当作已知值最优解)
    2.3 之前关注到的,什么时候初始化dp,确实是一个比较大的问题

题意:定义数 x = A n A n − 1 . . . A 2 A 1 x=A_nA_{n-1}...A_2A_1 x=AnAn1...A2A1,定义函数 F ( x ) = A n ∗ 2 n − 1 + A n − 1 ∗ 2 n − 2 + . . . + A 2 ∗ 2 + A 1 ∗ 1 F(x)=A_n*2^{n-1}+A_{n-1}*2^{n-2}+...+A_2*2+A_1*1 F(x)=An2n1+An12n2+...+A22+A11。然后,给出一个区间 [A,B](0<=A,B<1e9),求区间 [0,B] 内满足F(i)<=F(A) 的 i 的个数。
多组输入(T<=10000)。
题解

  1. 参考题解:F(x) (HDU-4734)(数位DP)
  2. 思路
    2.1 反正一般dp只需要更新一次就OK了
    2.2 所以这里要排除F(A)的干扰
    2.3 dp[pos][F(A)-num]而不是dp[pos][num](自己想一想)

代码

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
// #define int long long
// #define ll long long
#define pb push_back
#define dbg(x) cout << #x << "===" << x << endl
using namespace std;
const int N = 4599 + 5;  // 9*(2^9-1)=4599>1*2^9=512
const int MOD = 13;

int A, B, Ax, b[10 + 5];
int n, cnt, a[10 + 5];
int dp[10 + 5][N];
void init() {
    memset(dp, -1, sizeof(dp));
    b[0] = 1;
    for (int i = 1; i <= 10; i++) b[i] = b[i - 1] * 2;
}
int dfs(int pos, int num, int limit) {
    if (num > Ax) return 0;  //注意筛选
    if (pos == -1) return (num <= Ax);
    // Ax-num相当于剩余可用的容量
    /*
        !注意这里不是num而是Ax-num的原因:
        1、如果T=1的话,这里为多少都没有问题,但是这里T最多为10000。
        2、如果每组样例开始时都初始化dp数组,肯定TLE。
        3、如果dp[pos][num]只能表示pos位时前缀和位num的时候的(最优)解,但是Ax改变之后就不能再使用了,必须初始化
        4、而用dp[pos][Ax-num]则表示除去前pos位,后面还可以取Ax-num的最优解,显然这不随Ax改变而改变。
        ?懂了吧emm。
        !所以说,是否初始化,确实是一个很大的问题
    */
    if (!limit && dp[pos][Ax - num] != -1) return dp[pos][Ax - num];
    int res = 0;
    int up = limit ? a[pos] : 9;
    for (int i = 0; i <= up; i++) {
        res += dfs(pos - 1, (num + i * b[pos]), limit && (i == a[pos]));
    }
    if (!limit) dp[pos][Ax - num] = res;
    return res;
}
int solve(int y, int x) {
    cnt = 0, Ax = 0;
    while (y) {
        Ax += (y % 10) * b[cnt++];
        y /= 10;
    }
    // dbg(Ax);
    cnt = 0;
    while (x) {
        a[cnt++] = x % 10;
        x /= 10;
    }
    return dfs(cnt - 1, 0, 1);
}
signed main() {
    int T;
    cin >> T;
    init();
    for (int _ = 1; _ <= T; _++) {
        // memset(dp, -1, sizeof(dp));//初始化还是不,这是一个问题
        cin >> A >> B;
        int ans = solve(A, B);
        cout << "Case #" << _ << ": " << ans << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值