题意:“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][v1∗v2]=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;
}