PS:这题官方给的题解可能因为自己英语太差了没看懂。。。比赛时候写了个DP被卡了,看了好久才看懂大佬的代码,原来就是个暴力。。。
大致思路:先统计出两两配对的答案数,再对剩余的左括号暴力向后找能配对的右括号,还要统计一下以当前括号为起点可以向后连接多少个括号。直接看代码吧,注释写的很详细。
另外这题代码其实可以很短(根据官方题解给的结论,十行左右吧),感兴趣的同学可以去看官方题解。
#include <bits/stdc++.h>
#define int long long
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N=1e6+5,INF=1e16;
int n;
int s[N];
void solve() {
cin>>n;
for(int i=1;i<=n;i++)cin>>s[i];
int res=0;
//先将两两一组可以匹配的括号匹配掉,剩下的括号数组一定是x 0 0 y或者 x 0 y 0等等这种(每两个一定会有一个0)
for(int i=1;i<=n;i+=2){
int k=min(s[i],s[i+1]);
res+=k;
s[i]-=k,s[i+1]-=k;
}
//固定当前按i的剩余的左括号,计算对于当前的剩余的左括号 后面能有多少个剩余的右括号能匹配上
for(int i=1;i<=n;i+=2){
if(s[i+1])continue;//如果是0 x 这种说明没有剩余的左括号,直接跳过
int l=s[i],d=s[i],mx=s[i];//l表示当前未配对左括号的数量 ,mx表示遍历后方所有括号的过程中最多有多少左括号不能匹配
int sum=0;
for(int j=i+3;j<=n;j+=2){
sum+=s[j-1]-s[j];
if(sum<0)sum=0;//如果是 x 0 0 y这种(s[j-1]=0,s[j]=y),显然x 0 ,0 y这两块已经配 对的左括号可以连在一起
if(sum==0)res++;//之前已经配对的括号对可以连在一起,答案++
if(s[j]){//如果有右括号,说明可以跟之前的左括号配对
d-=s[j];
mx=min(mx,d);
if(d<0){
mx=0;//如果d<0说明右括号数量大于左括号数量,前面所有的左括号都能匹配,不会有剩余
break;
}
}
d+=s[j-1];//d表示当前还剩余多少未匹配的左括号
}
res+=l-mx;//l-mx对于i点的左括号,后面能跟这些左括号匹配的最大个数
}
cout<<res<<endl;
}
main(){
ios_base::sync_with_stdio(false), cin.tie(nullptr);
//init();
solve();
}```