Concurrently Balanced Strings G

建议降绿,完全不需要哈希和 dp。

套路地,把每一个左括号视为 \(+1\),右括号视为 \(-1\),做前缀和,记为 \(S_i\)。

对于一个区间 \([l,r]\),括号序列合法仅当 \(S_{l-1}=S_r\) 且 \(\min_{i\in[l,r]} \ge S_r\)。

第一个限制用 map 可以解决。

对于第二个限制,考虑枚举 \(r\),对于每一个 \(i\in[1,K]\) 都用单调栈求出左边第一个比 \(S_r\) 小的位置 \(P_i\),然后合法的 \(l\) 必然在 \([\max P+1,r-1]\) 之间取到。

随着 \(r\) 增大,\(P\) 单调不降,用一个队列不断 pop 前面不合法的 \(l\) 即可,时间复杂度 \(\mathcal O(n\log n)\)。

#include<bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define rep(i,l,r) for(int i=(l); i<=(r); ++i)
#define drep(i,r,l) for(int i=(r); i>=(l); --i)
using namespace std;
#define int long long
const int N=5e4+5;
int K,n,S,stk[N],L[N];
array<int,10>f[N];
map<array<int,10>,queue<int>>T;
char c;
signed main() {
	FASTIO;
    cin>>K>>n;
    rep(i,0,K-1) {
        int t=0;
        rep(j,1,n) {
            cin>>c,f[j][i]=f[j-1][i]+(c=='('?1:-1);
            while(t&&f[stk[t]][i]>=f[j][i]) --t;
            L[j]=max(L[j],stk[t]),stk[++t]=j;
        }
    }
    rep(i,1,n) {
        while(T[f[i]].size()&&T[f[i]].front()<=L[i]) T[f[i]].pop();
        S+=T[f[i]].size(),T[f[i]].push(i);
    }
    cout<<S<<'\n';
}
posted @ 2026-08-31 11:14  in-bustle  阅读(10)  评论(0)    收藏  举报