https://nanti.jisuanke.com/t/38223
题意
给出一个用火柴组成的表达式,由k个项和k-1个运算符组成。要求重组这些火柴,使得重组后的表达式结果最大。
重组的表达式要满足下面条件。
- 每项的位数必须相同,不能有前导零。
- 项数必须相同。
题解
预处理出
f[i][j][0/1]
:代表i位数用j根火柴组成的最大/最小数。
mx[k]: k根火柴可以组成的最大值。
f
[
i
]
[
j
]
[
0
]
=
m
a
x
{
f
[
i
−
1
]
[
j
−
k
]
[
0
]
∗
10
+
m
x
[
k
]
}
f[i][j][0] = max\{f[i-1][j-k][0]*10+mx[k]\}
f[i][j][0]=max{f[i−1][j−k][0]∗10+mx[k]}。
mn[k]: k根火柴可以组成的最小值。
f
[
i
]
[
j
]
[
1
]
=
m
i
n
{
f
[
i
−
1
]
[
j
−
k
]
[
1
]
∗
10
+
m
n
[
k
]
}
f[i][j][1] = min\{f[i-1][j-k][1]*10+mn[k]\}
f[i][j][1]=min{f[i−1][j−k][1]∗10+mn[k]}
dp[i][j][0/1]
: 前i项还剩j根火柴,前面运算符 是+/- 得出的最大值。
0: 代表前面是+,1: 代表前面是-,v[i]:第i项是几位数。
k: 该项用k根火柴。
d
p
[
i
]
[
j
]
[
0
]
=
m
a
x
{
d
p
[
i
−
1
]
[
j
−
k
−
2
]
[
0
]
+
f
[
v
[
i
]
]
[
j
−
k
−
2
]
[
0
]
,
d
p
[
i
−
1
]
[
j
−
k
−
1
]
[
1
]
+
f
[
v
[
i
]
]
[
j
−
k
−
1
]
[
0
]
}
dp[i][j][0] = max\{dp[i-1][j-k-2][0]+f[v[i]][j-k-2][0], dp[i-1][j-k-1][1]+f[v[i]][j-k-1][0]\}
dp[i][j][0]=max{dp[i−1][j−k−2][0]+f[v[i]][j−k−2][0],dp[i−1][j−k−1][1]+f[v[i]][j−k−1][0]}
d
p
[
i
]
[
j
]
[
1
]
=
m
a
x
{
d
p
[
i
−
1
]
[
j
−
k
−
1
]
[
0
]
+
f
[
v
[
i
]
]
[
j
−
k
−
1
]
[
1
]
,
d
p
[
i
−
1
]
[
j
−
k
−
1
]
[
1
]
+
f
[
v
[
i
]
]
[
j
−
k
−
1
]
[
1
]
}
dp[i][j][1] = max\{ dp[i-1][j-k-1][0]+f[v[i]][j-k-1][1], dp[i-1][j-k-1][1]+f[v[i]][j-k-1][1]\}
dp[i][j][1]=max{dp[i−1][j−k−1][0]+f[v[i]][j−k−1][1],dp[i−1][j−k−1][1]+f[v[i]][j−k−1][1]}
意思就是,如果第i项前面是+号,那么就要让该项加上尽量大的值,否则就加上尽量小的值。所以要预处理出f数组。
要特别注意初始化!!!
代码
#include <bits/stdc++.h>
using namespace std;
#define FOR0(a,b) for(int i = a; i < b; ++i)
#define FORE(a,b) for(int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 200;
const int mx[] = {0,0,1,7,4,5,9,8}; // i根火柴最大数是多少
const int mn[] = {0,0,1,7,4,2,0,8};
int tot, cnt;
char s[maxn];
ll f[maxn][705][2]; // 第i个数还剩j根火柴的 最大/最小 数
ll dp[maxn][705][2]; // 前i个数字 还剩 j 根火柴 组成的式子最大是多少
void init() {
for(int i = 1; i <= 10; ++i)
for(int j = 0; j <= 700; ++j)
f[i][j][0] = -1e14, f[i][j][1] = 1e14;
f[0][0][0] = f[0][0][1] = 0;
for(int i = 1; i <= 10; ++i) {
for(int j = 2; j <= 100; ++j) {
for(int k = 2; k <= 7; ++k) {
if(j-k >= 0) {
f[i][j][0] = max(f[i][j][0], f[i-1][j-k][0]*10+mx[k]);
f[i][j][1] = min(f[i][j][1], f[i-1][j-k][1]*10+mn[k]);
}
}
// cout << i <<" " << j << " " << f[i][j][1] << endl;
}
}
}
int main() {
int T;
scanf("%d", &T);
init();
while(T--) {
int n;
scanf("%d", &n);
scanf("%s", s);
tot = cnt = 0;
int len = strlen(s);
vector<int> v;
int t = 0;
for(int i = 0; i < len; ++i) {
if(s[i] >= '0' && s[i] <= '9') {
t++;
}
if(s[i] == '1') tot += 2;
else if(s[i] == '2') tot += 5;
else if(s[i] == '3') tot += 5;
else if(s[i] == '4') tot += 4;
else if(s[i] == '5') tot += 5;
else if(s[i] == '6') tot += 6;
else if(s[i] == '7') tot += 3;
else if(s[i] == '8') tot += 7;
else if(s[i] == '9') tot += 6;
else if(s[i] == '0') tot += 6;
else if(s[i] == '+') {tot += 2; cnt++; v.push_back(t); t = 0;}
else if(s[i] == '-') {tot += 1; cnt++; v.push_back(t); t = 0;}
}
v.push_back(t);
for(int i = 0; i < v.size(); ++i) for(int j = 0; j <= tot; ++j) dp[i][j][0] = dp[i][j][1] = -1e14;
for(int j = 2; j <= tot; ++j) {
dp[0][j][1] = dp[0][j][0] = f[v[0]][j][0];
// cout << 0 <<" " << j << " " << dp[0][j][0] << endl;
}
for(int i = 1; i < v.size(); ++i) {
for(int j = 0; j <= tot; ++j) {
for(int k = 0; k <= j; ++k) {
if(k+2 <= j) {
dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-k-2][0]+f[v[i]][k][0]);
dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-k-2][1]+f[v[i]][k][0]);
// cout << dp[i-1][j-k-2][0]<<" " << dp[i-1][j-k-2][1] << " "<< f[v[i]][k][0] << endl;
// cout << dp[i][j][0] << endl;
}
if(k+1 <= j) {
dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-k-1][0]-f[v[i]][k][1]);
dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-k-1][1]-f[v[i]][k][1]);
}
}
// cout << i << " " << j <<" " << dp[i][j][1] << endl;
}
}
ll ans = -1e14;
// cout << cnt << endl;
for(int i = 0; i <= tot; ++i) {
ans = max(ans, max(dp[cnt][i][0],dp[cnt][i][1]));
}
printf("%d\n", ans);
}
return 0;
}