明显数位DP,一开始是用了二分+数位DP,结果T了,过不了,后面看了网上题解,发现这种题其实都可以用构造来实现,先确定位数,然后从高位从小到大枚举放什么数字即可
代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; int t, X, Y; ll L, R; int bit[22], bn; void get(ll x) { bn = 0; if (x == 0) bit[bn++] = 0; while (x) { bit[bn++] = x % 10; x /= 10; } for (int i = 0; i < bn / 2; i++) swap(bit[i], bit[bn - i - 1]); } ll dp[22][22][22], DP[22][22][22]; ll solve(ll num) { get(num); memset(dp, 0, sizeof(dp)); int xnum = 0, ynum = 0, flag = 0; for (int i = 0; i < bn; i++) { for (int x = 0; x <= X; x++) { for (int y = 0; y <= Y; y++) { if (dp[i][x][y] == 0) continue; for (int k = 0; k < 10; k++) { if (k == 4) dp[i + 1][x + 1][y] += dp[i][x][y]; else if (k == 7) dp[i + 1][x][y + 1] += dp[i][x][y]; else dp[i + 1][x][y] += dp[i][x][y]; } } } if (flag) continue; for (int k = 0; k < bit[i]; k++) { if (k == 4) dp[i + 1][xnum + 1][ynum]++; else if (k == 7) dp[i + 1][xnum][ynum + 1]++; else dp[i + 1][xnum][ynum]++; } if (bit[i] == 4) xnum++; else if (bit[i] == 7) ynum++; if (xnum > X || ynum > Y) flag = 1; } if (xnum == X && ynum == Y) dp[bn][X][Y]++; return dp[bn][X][Y]; } void init() { DP[0][0][0] = 1; for (int i = 0; i <= 20; i++) { for (int j = 0; j <= 20; j++) { for (int k = 0; k <= 20; k++) { DP[i + 1][j + 1][k] += DP[i][j][k]; DP[i + 1][j][k + 1] += DP[i][j][k]; DP[i + 1][j][k] += DP[i][j][k] * 8; } } } } ll cal(ll num) { int len = 0; while (1) { if (DP[len][X][Y] >= num) break; len++; } ll ans = 0; int sx = X, sy = Y; for (int i = len; i; i--) { for (int x = 0; x < 10; x++) { int vi = i - 1; int vx = sx - (x == 4); int vy = sy - (x == 7); if (vx < 0 || vy < 0) continue; if (DP[vi][vx][vy] >= num) { ans = ans * 10 + x; sx = vx; sy = vy; break; } num -= DP[vi][vx][vy]; } } return ans; } int main() { init(); int cas = 0; scanf("%d", &t); while (t--) { scanf("%I64d%I64d%d%d", &L, &R, &X, &Y); int q; ll k; scanf("%d", &q); printf("Case #%d:\n", ++cas); while (q--) { scanf("%I64d", &k); ll a = solve(L); if (solve(R) - a < k) { printf("Nya!\n"); continue; } printf("%I64d\n", cal(a + k)); } } return 0; }