题目链接
题目描述
给定一个无限循环的字符串
1145141919
1145141919
1145141919,你可以取一个前缀并在中间添加
+
,
∗
,
(
,
)
+,*,(,)
+,∗,(,)使其变成一个运算表达式,每次询问一个
n
n
n,输出构成表达式结果等于
n
n
n的最小前缀,若不存在输出
−
1
-1
−1
思路
考虑区间dp,
s
e
t
<
i
n
t
>
d
p
[
l
]
[
r
]
set<int>dp[l][r]
set<int>dp[l][r]表示区间为
[
l
.
r
]
[l.r]
[l.r]之间所有可能存在的数,最后去求一下每个数最小的前缀即可。在考虑存数字时,极限就是
(
r
−
l
+
1
≤
4
)
(r-l+1\leq4)
(r−l+1≤4)。赛后题解给出只要跑到13即可,比赛时推不出来可以本地打表再交。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5010;
int res[N];
string s = " 1145141919114514191911451419191145141919";
set<int> f[20][20];
void dfs(int l, int r) {
if((int)f[l][r].size() != 0) return;
if(r - l + 1 <= 4) {
int num = 0;
for(int i = l; i <= r; i++) {
num = num * 10 + (s[i] - '0');
}
f[l][r].insert(num);
}
for(int i = l; i < r; i++) {
dfs(l, i); dfs(i + 1, r);
for(auto a : f[l][i]) {
for(auto b : f[i + 1][r]) {
if(a + b <= 5000) f[l][r].insert(a + b);
if(a * b <= 5000) f[l][r].insert(a * b);
}
}
}
}
void init() {
dfs(1, 13);
memset(res, 0x3f, sizeof res);
for(int i = 1; i <= 13; i++) {
for(auto x : f[1][i]) {
res[x] = min(res[x], i);
}
}
for(int i = 1; i <= 5000; i++) {
if(res[i] > 20) res[i] = -1;
}
}
void solve() {
int n; scanf("%d", &n);
printf("%d\n", res[n]);
}
int main() {
init();
int t; cin >> t; while(t--)
solve();
return 0;
}