链接:
https://vjudge.net/problem/HDU-4734
题意:
For a decimal number x with n digits (A nA n-1A n-2 ... A 2A 1), we define its weight as F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A 1 * 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的最大值在5000以内。
考虑每次a都是不同的,为了减少mem的时间,我们让记录他的和变成记录当前值和F(a)的差,这样就具有通用性。不用每次的mem时间。
代码:
// #include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<vector> #include<string.h> #include<set> #include<queue> #include<algorithm> #include<math.h> using namespace std; typedef long long LL; const int MOD = 1e9+7; const int MAXN = 1e6+10; LL F[15][5000]; LL dig[15]; LL m[15]; LL a, b, n, tot; LL Dfs(int pos, LL sta, bool lim) { if (pos == -1) return (sta >= 0); if (sta < 0) return 0; if (!lim && F[pos][sta] != -1) return F[pos][sta]; int up = lim ? dig[pos] : 9; LL ans = 0; for (int i = 0;i <= up;i++) ans += Dfs(pos-1, sta-i*m[pos], lim && i == up); if (!lim) F[pos][sta] = ans; return ans; } LL Solve(LL x) { int p = 0; while(x) { dig[p++] = x%10; x /= 10; } return Dfs(p-1, tot, 1); } int main() { // freopen("test.in", "r", stdin); m[0] = 1; for (int i = 1;i < 15;i++) m[i] = 2*m[i-1]; memset(F, -1, sizeof(F)); int t, cnt = 0; scanf("%d", &t); while(t--) { scanf("%lld %lld", &a, &b); tot = 0; int p = 0; while(a) { tot += (a%10)*m[p++]; a /= 10; } printf("Case #%d: %lld\n", ++cnt, Solve(b)); } return 0; }