正题
题目链接:https://www.luogu.org/problemnew/show/P4989
题目大意
一个二进制数两两配对,要求
- 配对的数不能交叉(用同一个区间但不包含)
- 0在前1在后
要求配对最多的情况下所有配对的距离之和最远。
解题思路
将0视为左括号,1视为右括号,题目变为括号匹配问题。
我们考虑贪心,先是交叉的问题,我们发现如果两个交叉了,我们让他们反过来配对(配对方的那个)的话答案并不会改变。所有我们不要考虑交叉问题。
那我们开始做,首先不考虑配对最多,我们可以开一个小根堆,存储目前所有已经匹配的右括号还有未左括号的位置。然后我们每次到一个右括号时,取出最小的那个与其匹配并计算多出来的代价。然后从新丢入堆中。
这是距离之和最远,但是配对最多怎么办,那么我们定义权值,小根堆维护权值。对于已经匹配的右括号我们权值就是它的位置;对于没有匹配的左括号,我们让它的权值加上一个−inf-inf−inf就可以了。
这样就可以保证优先匹配没有匹配的且权值最大。
时间复杂度O(nlogn)O(n\ log\ n)O(n log n)
codecodecode
#include<cstdio>
#include<queue>
#include<iostream>
using namespace std;
struct node{int wz,w;
};
bool operator <(const node &a,const node &b)
{return a.w<b.w;}
priority_queue<node> q;
int n,ans,a[1000];
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){char c;cin>>c;a[i]=c-'0';}for(int i=1;i<=n;i++){if(!a[i]) q.push((node){i,233333333-i});else{if(q.empty()) continue;ans+=i-q.top().wz;q.pop();q.push((node){i,-i});}}printf("%d",ans);
}