题解:CF1976D Invertible Bracket Sequences
可以在 cnblog 中阅读。
题意
给一个合法括号序列,问有多少区间 \([l,r]\),使得将区间内的每个括号翻转后,括号序列仍合法。
分析
十分套路地,我们将 (
看成 \(+1\),将 )
看成 \(-1\),则一个括号序列合法的充要条件是转换后的序列满足:
- 前缀和任意位置非负;
- 最后一项为 \(0\)。
考虑翻转括号序列意味着什么。翻转后 \(+1,-1\) 对调,为保证条件二,需要满足区间内的 \(+1,-1\) 数量相等,条件一则可以通过前缀和折线图来思考。
反转后,折线图的向上变为向下,向下变为向上,实际上就是上下对称地翻转过来,对称轴就是区间的左右端点较小值。不合法当且仅当折下去低于 x 轴。
这样条件就明朗了,我们可以将前缀和丢进 map 里面,在右端点处统计对答案的贡献。最后再把折下去不合法的从 map 里扔出去。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
void solve()
{
string s; cin>>s;
map<int,int> cnt;
cnt[0]=1;
int st=0,ans=0;
for(char c:s)
{
if(c=='(') st++;
else st--;
ans+=cnt[st];
cnt[st]++;
while((*cnt.begin()).first*2<st) cnt.erase(cnt.begin());
}
cout<<ans<<endl;
}
signed main()
{
IOS;
int T; cin>>T;
while(T--) solve();
return 0;
}