- 这个专题的前几篇博客熟悉了数位DP的形式。
- 现在慢慢来理解:
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=AnAn−1...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)=An∗2n−1+An−1∗2n−2+...+A2∗2+A1∗1。然后,给出一个区间 [A,B](0<=A,B<1e9),求区间 [0,B] 内满足F(i)<=F(A) 的 i 的个数。
多组输入(T<=10000)。
题解:
- 参考题解:F(x) (HDU-4734)(数位DP)
- 思路:
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;
}