HDU 6831 Fragrant numbers (区间dp+预处理)

题意:“1145141919” 的无穷串,给出一个n,要求选最少的num,使得前num个数中间添加任意括号、加号、乘号,计算结果等于n。

题解:区间dp+预处理
d p [ i ] [ j ] [ v a l ] dp[i][j][val] dp[i][j][val] [ i , j ] [i, j] [i,j]区间内是否能计算出 v a l val val

于是可得转移方程:
d p [ i ] [ j ] [ v 1 + v 2 ] = d p [ i ] [ m i d ] [ v 1 ] 与 d p [ m i d + 1 ] [ j ] [ v 2 ] dp[i][j][v1+v2]=dp[i][mid][v1]与dp[mid+1][j][v2] dp[i][j][v1+v2]=dp[i][mid][v1]dp[mid+1][j][v2]
d p [ i ] [ j ] [ v 1 ∗ v 2 ] = d p [ i ] [ m i d ] [ v 1 ] 与 d p [ m i d + 1 ] [ j ] [ v 2 ] dp[i][j][v1*v2]=dp[i][mid][v1]与dp[mid+1][j][v2] dp[i][j][v1v2]=dp[i][mid][v1]dp[mid+1][j][v2]

最多只需要前12位就能构造出所有数,除了3、7。预处理一下。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
const int maxn = 13;
const int maxm = 5005;
string s = "0114514191911";
int t, n, dp[maxn][maxn][maxm], ans[maxm];
int main() {
    
    
	for (int i = 1; i < maxn; i++) {
    
    
		int x = 0;
		for (int j = i; j < maxn; j++) {
    
    
			x = x * 10 + s[j] - 48;
			if (x > maxm) break;
			if (x < maxm) dp[i][j][x] = 1;
		}
	}
	for (int i = maxn - 1; i >= 1; i--) {
    
    
		for (int j = i; j < maxn; j++) {
    
    
			for (int mid = i; mid < j; mid++) {
    
    
				for (int k = 1; k < maxm; k++) {
    
    
					if (!dp[i][mid][k]) continue;
					for (int p = 1; p < maxm; p++) {
    
    
						if (!dp[mid + 1][j][p]) continue;
						if (k + p < maxm) dp[i][j][k + p] = 1;
						if (k * p < maxm) dp[i][j][k * p] = 1;
					}
				}
			}
		}
	}
	for (int i = 1; i < maxn; i++) {
    
    
		for (int j = 1; j < maxm; j++) {
    
    
			if (dp[1][i][j] && !ans[j]) ans[j] = i;
		}
	}
	scanf("%d", &t);
	while (t--) {
    
    
		scanf("%d", &n);
		printf("%d\n", ans[n] == 0 ? -1 : ans[n]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43680965/article/details/107851771