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';
}

浙公网安备 33010602011771号