现在的位置: 首页 > 综合 > 正文

HDU 3943 K-th Nya Number(数位DP + 构造)

2018年10月12日 ⁄ 综合 ⁄ 共 1633字 ⁄ 字号 评论关闭

明显数位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;
}

抱歉!评论已关闭.