[省选联考2022] 序列变换
好题。
考虑先对括号包含关系对括号序列进行构树。
那么考虑实际上一/二操作的实质是:
在同一层中:每次可以选择两个点 \((A,B)\),以 \(val_A * x + val_B * y\) 代价把 \(B\) 丢到下一层,要求每一层只有一个数。
考虑分类讨论:
设本层有 \(m\) 个,最小值是 \(mn\),最大值是 \(mx\) .
\(x = 1,y = 1\)
一个显然的最优方案是:
每个数都会有一次代价,然后每下放一个数都会有一个另外的数的代价,那么答案有:
\((m - 2) * mn + sum\)
即每次留在这层的都是 \(mx\) 。
\(x = 0,y = 1\)
显然也每次留在这层的是 \(mx\),答案有:\(sum - mx\)
\(x = 1,y = 0\)
听说原本只有这么一种情况的。
考虑一种贪心:每次都往下以最小值的代价传数,最后看保留的是哪一位数:
考虑每个数最终都会到一个位置保留,除了最后一个位置不用付代价外都要付代价
那么自然想到把最大值给留到最后。
但是我们发现这样在只有两个的时候不成立,因为如果传最大值,而不传最小值有可能影响后续取数答案。
那么考虑找到第一个加上上面传下的数量大于\(2\)的位置然后分段,那么从前面来的要么是前缀最大值,要么是前缀最小值,考虑两种情况都跑即可。
小细节:如果有全局最大值,取位置最后的,来保证最小值影响范围大。
点击查看代码
//晦暗的宇宙,我们找不到光,看不见尽头,但我们永远都不会被黑色打倒。——Quinn葵因
#include<bits/stdc++.h>
#define ll long long
#define N 400005
char s[N << 1];
int n,x,y;
inline int read(){int x;scanf("%d",&x);return x;}
int now = 0;
using std::vector;
vector<ll>G[N];
using std::multiset;
multiset<ll>S;
ll siz,sum,mn,mx;
#define IT std::set<ll>::iterator
ll ans;
inline void sub1(){
for(int i = 1;i <= n;++i){
for(auto v : G[i])
S.insert(v),siz ++ ,sum += v;
IT it = S.begin();mn = *it;it = S.end();--it;mx = *it;
ans = ans + sum + (siz - 2) * mn;
S.erase(it);siz -= 1;sum -= mx;
}
}
ll MX;
inline void sub2(){
for(int i = 1;i <= n;++i){
for(auto v : G[i])
S.insert(v),siz ++ ,sum += v;
IT it = S.begin();mn = *it;it = S.end();--it;mx = *it;
ans = ans + sum - mx;
S.erase(it);siz -= 1;sum -= mx;
}
}
int d;
inline ll work(int now){
// std::cout<<"WORK "<<now<<"\n";
ll res = 0;
for(int i = now;i <= n;++i){
for(auto v : G[i])
S.insert(v),siz ++ ,sum += v;
IT it = S.begin();mn = *it;it = S.end();--it;mx = *it;
if(i >= d){--it,mx = *it;res = res + (siz - 2) * mn + mx;S.erase(it);siz -= 1;sum -= mx;}
else{res = res + (siz - 2) * mn + mx;S.erase(it);siz -= 1;sum -= mn;}
// std::cout<<"DEP "<<mx<<" "<<mn<<" "<<res<<"\n";
}
return res;
}
int flg;
ll SI;
ll MN;
inline void sub3(){
//nothing haha
for(int i = 1;i <= n;++i)
for(auto v : G[i]){if(v > MX)MX = v,d = i;}
ans = work(1);
S.clear();sum = siz = 0;
flg = 0;
for(int i = 1;i <= n;++i){
if(G[i].size() != 1 && flg){
MX = 0;
MN = *S.begin();
for(int j = i;j <= n;++j)
for(auto v : G[j]){if(v > MX)MX = v,d = i;}
ans = std::min(ans,SI - MN + work(i));return ;
}
if(G[i].size() == 2)flg = 1;
for(auto v : G[i])
S.insert(v),siz ++ ,sum += v,SI += flg * v;
IT it = S.end();--it;mx = *it;
S.erase(it);siz -= 1;sum -= mx;
}
}
int main(){
// freopen("bracket.in","r",stdin);
// freopen("bracket.out","w",stdout);
scanf("%d%d%d",&n,&x,&y);
scanf("%s",s + 1);
for(int i = 1;i <= n * 2;++i){
if(s[i] == '(')now ++ ;
if(s[i] == ')')now -- ;
if(s[i] == '(')G[now].push_back(read());
}
if(x == 1 && y == 1)sub1();
if(x == 0 && y == 1)sub2();
if(x == 1 && y == 0)sub3();
std::cout<<ans<<"\n";
}