题意:For a decimal number x with n digits (AnAn-1An-2 … A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + … + A2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).
分析:和上一篇差不多,减着找答案;
权值为
F(x)
F
(
x
)
,
dp[pos][sta]:维护前pos位F(x)<=sta的个数,直接dfs下去。
d
p
[
p
o
s
]
[
s
t
a
]
:
维
护
前
p
o
s
位
F
(
x
)
<=
s
t
a
的
个
数
,
直
接
d
f
s
下
去
。
PS:数位DP要注意dfs的出口,以及dp[pos][sta]所表示的意义,套着模板解决一般问题就够了,本质就是记忆化搜索+剪枝。
#pragma GCC optimize ("O3")
#pragma GCC optimize ("O2")
#include <bits/stdc++.h>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define met(s) memset(s, 0, sizeof(s))
#define rep(i, a, b) for(int i = a; i <= b; ++i)
template <class T> inline void scan_d(T &ret) {
char c; ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9') {
ret = ret * 10 + (c - '0'), c = getchar();}}
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int MAXN = 1e4 + 10;
int a[10], dp[10][MAXN];
inline int dfs(int pos, int sta, int k, int limit) {
if(pos < 0 && sta >= 0) return 1;
if(pos < 0 || sta < 0) return 0;
if(!limit && dp[pos][sta] >= 0) return dp[pos][sta];
int up = limit ? a[pos] : 9;
int ans = 0;
for(int i = 0; i <= up; ++i) {
ans += dfs(pos - 1, sta - i * (1 << pos), k, limit && i == up);
}
if(!limit) dp[pos][sta] = ans;
return ans;
}
inline void solve(int x, int k) {
int p = 0;
while(x) {
a[p++] = x % 10;
x /= 10;
}
printf("%d\n", dfs(p - 1, k, k, 1));
}
inline int so(int x) {
int ans = 1, cnt = 0;
while(x) {
cnt += ans * (x % 10);
x /= 10;
ans <<= 1;
}
return cnt;
}
int main() {
memset(dp, -1, sizeof(dp));
int T, cas = 1; scanf("%d", &T);
while(T--) {
int A, B;
scanf("%d %d", &A, &B);
int ans = so(A);
printf("Case #%d: ", cas++);
solve(B, ans);
}
return 0;
}