题解:P17543 [JAG 2026 Summer Camp #2] Deque Bracket Optimization
这个是反悔贪心?是不是不太像,感觉说直接贪是不是更自然。
首先考虑问题的静态情形怎么做。思考一个括号序列什么时候是合法的:当且仅当前 \(2i - 1\) 个字符中有至少 \(i\) 个 (。然而 \(i\) 和 \(2i - 1\) 不是倍数关系,不太好。但是注意到第一个位置一定是 (,最后一个位置一定是 ),所以不用考虑。所以我们可以把第一个和最后一个位置去除,在执行完去除操作所剩下的括号序列上,前 \(2i\) 个字符有至少 \(i\) 个 (。
那么我们从左往右考虑,维护目前未被确定为 ( 的所有位置(下文称为“未确定集合”)。维护一个变量 \(i\) 从左往右扫描,每次将 \(i, i+1\) 先加入未被确定为 ( 的集合,然后直接贪心地从未确定集合中选出 \(w_j\) 最大的 \(j\) 确定为左括号,随后将 \(i\) 增加 \(2\)。
这么做为什么正确?发现,一个决策会影响一个后缀,也就是一个 \(i\) 加入后,后续的所有位置都可以选择这个 \(i\) 产生贡献。这就意味着如果我在某个位置没有选择最优决策 \(j\),而选择了一个决策 \(j'\),那么我们把 \(i\) 处的决策调整成 \(j\),然后在后续的一个位置把决策修改为 \(j'\),这样做是不劣的。至此我们说明了这个做法的正确性。下文中这个做法被称为做法 \(1\)。
至此可以解决只有 \(1\) 或 \(3\) 操作的做法。
接下来考虑同时存在 \(1, 3\) 的做法。注意到,这个问题其实完全等价于另外一个问题:求所有括号序列中,所有 ) 对应位置的 \(w\) 之和的最小值。这个问题的做法也是对称的:我们从右往左扫描,维护目前还未确定为 ) 的位置集合,每次取出集合中 \(w\) 最小的位置即可。下文中这个做法被称为做法 \(2\)。
然后发现这两个做法可以合并!具体地,我们发现做法 \(1\) 中未被确定为 ( 的集合就是目前确定为 ) 的集合,做法 \(2\) 中未被确定为 ) 的集合就是目前确定的 ( 的集合,因此这两个集合是互补的!因此假设目前 ( 的集合为 \(S_l\),) 的集合是 \(S_r\)。则当我在末尾加入元素的时候,我们使用做法 \(1\),将我加入的元素加入 \(S_r\),随后弹出 \(S_r\) 的最大值加入 \(S_l\);当我在开头加入元素的时候,我们使用做法 \(2\),将我加入的元素加入 \(S_l\),随后弹出 \(S_l\) 的最小值加入 \(S_r\)。
至此解决了同时存在 \(1, 3\) 的情况。
再考虑操作 \(2\),你发现由于我们做法 \(1\),做法 \(2\) 都只能支持一次在同一方加入 \(2\) 个元素,然而操作 \(2\) 是分别在左端、右端各加入一个元素,使用已有的做法做不了。
但是发现,我们可以把上述 \(S_l, S_r\) 及其对应的操作封装为一个数据结构,然后维护两个数据结构 \(\operatorname{out}, \operatorname{in}\),分别表示现在整个序列对应的数据结构,以及现在的序列去除首尾元素后对应的数据结构。则当我在首尾各加入一个元素时,在原来 \(\operatorname{in}\) 的首尾各加入两个元素之后就可以得到新的 \(\operatorname{out}\),而原来的 \(\operatorname{out}\) 就是新的 \(\operatorname{in}\),这样在首尾各加入一个元素的情况也得到解决。
至此问题在 \(O(q \log q)\) 的时间内得到解决!
#include<bits/stdc++.h>
#define endl '\n'
#define N 400006
using namespace std;
using i64=long long;
int q;
struct DS {
int l,r; i64 sum;
priority_queue<int> rb;
priority_queue<int,vector<int>,greater<int> > lb;
DS():l(-2e9),r(-2e9),sum(0) {}
void push_back(int x,int y)
{
if(l==-2e9)return l=x,r=y,(void)0;
rb.push(r),rb.push(x),r=y;
lb.push(rb.top()),sum+=rb.top(),rb.pop();
}
void push_front(int x,int y)
{
if(l==-2e9)return l=y,r=x,(void)0;
lb.push(l),lb.push(x),sum+=l+x,l=y;
rb.push(lb.top()),sum-=lb.top(),lb.pop();
}
};
void solve()
{
scanf("%d",&q);
DS in,out; deque<int> dq;
for(int i=1,o,x,y;i<=q;i++)
{
scanf("%d%d%d",&o,&x,&y);
if(o==3||o==2&&i==1)
{
out.push_back(x,y);
if(i>1)in.push_back(dq.back(),x);
dq.push_back(x),dq.push_back(y);
} else if(o==1) {
out.push_front(x,y);
if(i>1)in.push_front(dq.front(),x);
dq.push_front(x),dq.push_front(y);
} else {
in.push_front(dq.front(),x),in.push_back(dq.back(),y);
swap(in,out),dq.push_front(x),dq.push_back(y);
}
printf("%lld\n",out.l+out.sum);
}
}
main()
{
int T; scanf("%d",&T);
while(T--)solve();
return 0;
}

浙公网安备 33010602011771号