hihocoder #1301 : 筑地市场 数位dp+二分
题目链接:
http://hihocoder.com/problemset/problem/1301?sid=804672
题解:
二分答案,每次判断用数位dp做。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; typedef long long LL; const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; //dp[x][0]表示高位还没有出现4,7。 //dp[x][1]表示高位已经出现4,7了。 LL dp[22][2]; bool vis[22][2]; LL k; int num[22]; //z表示高位是不是刚好在最大的边界上。 LL dfs(int cur, int y, int z) { if (cur == -1 && y) return 1; if (cur == -1) return 0; if (vis[cur][y] && !z) return dp[cur][y]; int e = z ? num[cur] : 9; LL res = 0; for (int i = 0; i <= e; i++) { res += dfs(cur - 1, y || i == 4 || i == 7, z && (i == e)); } if (!z) { dp[cur][y] = res; vis[cur][y] = 1; } return res; } bool ok(LL x) { int tot = 0; while (x) { num[tot++] = x % 10; x /= 10; } memset(dp, 0, sizeof(dp)); memset(vis, 0, sizeof(vis)); LL res = dfs(tot - 1, 0, 1); return res<k; } int main() { while (scanf("%lld", &k) == 1) { LL l = 1, r = INFLL; //printf("r:%lld\n", r); while (l + 1 < r) { LL mid = l + (r - l) / 2; if (ok(mid)) l = mid; else r = mid; } printf("%lld\n", l + 1); } return 0; }