题意
给你一个长度为 N N N 的 a a a 数组,数组里面都是 [ 0 , 9 ] [0,9] [0,9] 的自然数,允许你添加 + + +、 − - −、 ∗ * ∗号,现在你希望式子最大
N ≤ 1 0 5 N \leq 10^5 N≤105
分析
分析一下,只有
+
+
+和
∗
*
∗的情况比较麻烦
考虑麻烦的点,
0
0
0的左右两边肯定都是
+
+
+号
但是
1
1
1的左右两边,可以是
+
+
+,也可以是
∗
*
∗,
+
+
+是两边的数都不太大的情况,*是两边的数都大,就需要
∗
*
∗
而且可以发现,
1
1
1的左右两边,肯定是同号的。
所以把
0
0
0作为断点,找到区间
[
l
,
r
]
[l,r]
[l,r],然后发现前缀和后缀的1肯定都是需要
+
+
+的,因为没有
∗
*
∗的必要。
中间数数有多少个
>
1
>1
>1的数,如果
>
28
>28
>28个左右的话,那么中间全都用乘号连接。
否则的话,可以考虑
d
p
dp
dp来填。
d
p
[
i
]
dp[i]
dp[i]表示当前等式到达第
i
i
i位的最大值,记录一个路径
p
a
t
h
path
path
容易写出:
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
1
]
+
a
[
i
]
,
d
p
[
j
−
1
]
+
Π
k
=
j
i
a
[
k
]
)
)
dp[i] = max(dp[i-1] + a[i] , dp[j-1] + \Pi_{k=j}^{i} a[k]))
dp[i]=max(dp[i−1]+a[i],dp[j−1]+Πk=jia[k]))
发现
a
[
i
]
=
1
a[i] = 1
a[i]=1其实可以直接从上一个转移过来的,实际枚举j的个数至多有
28
28
28个。
d
p
dp
dp的时候要用__int128
代码
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
#define int long long
using namespace std;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(5e5) + 10;
const int mod = 998244353;
const int inf = 1e18 + 10;
const long double pi = acos(-1);
inline int rd() {
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
int a[N],len,n; char ans[N],s[N];
void wr() {
for(int i=1;i<n;i++) printf("%lld%c",a[i],ans[i]);
printf("%lld\n",a[n]);
}
bool check(char ch) {
for(int i=1;i<=len;i++) if(s[i] == ch) return 1;
return 0;
}
__int128 dp[N],path[N],mul[N];
void solve(int l,int r) {
if(l>r) return ;
dp[l-1] = 0; vector<int> v;
mul[l-1] = 1; for(int i=l;i<=r;i++) mul[i] = a[i] * mul[i-1];
for(int i=l;i<=r;i++) {
// printf("%lld ",dp[i]); puts("");
if(a[i] == 1) dp[i] = dp[i-1] + 1,path[i] = i;
else {
if(v.size() == 0){dp[i] = dp[i-1] + a[i]; path[i] = i;}
else {
int p = 0;
for(int j=1;j<(int)v.size();j++) {
if(dp[v[j]-1] + (mul[i] / mul[v[j]-1]) > dp[v[p]-1] + (mul[i] / mul[v[p]-1]) )
p = j;
}
if(dp[v[p]-1] + (mul[i] / mul[v[p]-1]) >= dp[i-1] + a[i]) {
dp[i] = dp[v[p]-1] + (mul[i] / mul[v[p]-1]);
path[i] = v[p];
}else {
dp[i] = dp[i-1] + a[i];
path[i] = i;
}
}
v.push_back(i);
}
}
// for(int i=l;i<=r;i++) printf("%lld ",dp[i]); printf("\n");
// for(int i=l;i<=r;i++) printf("%lld ",path[i]); puts("");
int pos = r;
while(pos >= l) {
int pre = path[pos];
for(int j=pre;j<pos;j++) ans[j] = '*';
ans[pre-1] = '+';
pos = pre - 1;
}
}
void solve() {
int cnt = 0,lst = 1;
for(int i=1;i<=n+1;i++) {
if(a[i] == 0) {
ans[i-1] = ans[i] = '+';
if(cnt > 28) {
int l = lst; int r = i-1;
while(a[l] == 1 && l <= r) ans[l] = '+',l++;
while(a[r] == 1 && l <= r) ans[r-1] = '+',r--;
for(int j=l;j<r;j++) ans[j] = '*';
}
else solve(lst , i-1);
cnt = 0 , lst = i+1;
}
else if(a[i] > 1){
cnt++;
}
}
wr();
}
signed main() {
n = rd();
for(int i=1;i<=n;i++) a[i] = rd();
scanf("%s",s+1); len = strlen(s+1);
if(len == 1) {
memset(ans,s[len],sizeof(ans));
wr(); return 0;
}else if(check('+') && check('*')) solve();
else if(check('-') && check('*')) {
int pos = n+1;
for(int i=2;i<=n;i++) if(a[i] == 0){pos = i; break;}
memset(ans,'*',sizeof(ans));
if(pos == n+1) {
wr(); return 0;
}else {
for(int i=1;i<pos-1;i++) ans[i] = '*';
ans[pos-1] = '-';
for(int i=pos;i<n;i++) ans[i] = '*';
wr(); return 0;
}
}else if(check('+') && check('-')) {
memset(ans,'+',sizeof(ans));
for(int i=1;i<n;i++) printf("%lld%c",a[i],ans[i]);
printf("%lld\n",a[n]);
}
}