不妨令:
num_U:字符‘U’的数目
num_D:字符‘D’的数目
num_L:字符‘L’的数目
num_R:字符‘R’的数目
我们称呼区间内 num_U 等于 num_D 且 num_L 等于 num_R 的连续区间 [l,r] 为 ”好区间“
给定我们一个只由 ‘U’ ‘D’ ‘L’ ‘R’ 四种字符组成的字符串,问:这样的“好区间”有多少个 ?
对于好区间 [l,r],显然有:
sum_U[r] - sum_U[l-1] = sum_D[r] - sum_D[l-1]
sum_L[r] - sum_L[l-1] = sum_R[r] - sum_R[l-1]
转化得:
sum_U[r] - sum_D[r] = sum_U[l-1] - sum_D[l-1]
sum_R[r] - sum_L[r] = sum_R[l-1] - sum_L[l-1]
所以我们不妨枚举区间右端点 r ,看有几个左端点可以与 r 构成“好区间”,然后累加,最后得到答案
那么如何判断 左端点 l 是否可以与 右端点 r 构成“好区间” 呢 ?
因为 “好区间”的 l 与 r 满足:
sum_U[r] - sum_D[r] = sum_U[l-1] - sum_D[l-1] 且 sum_R[r] - sum_L[r] = sum_R[l-1] - sum_L[l-1]
而对于 r 已经有了:first:sum_U[r] - sum_D[r] 和 second:sum_R[r] - sum_L[r]
所以,我们只需要统计 r 前 ,sum_U[i]- sum_D[i] = first 且 sum_R[i] - sum_L[i] = second 的点数既可
我们可以用 map 与 pair 来辅助我们,这更加方便
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int N = 1e5+10;
PII p[N];
char s[N];
map<PII,ll> ma;
int sum_L[N],sum_R[N];
int sum_U[N],sum_D[N];
int n;
int main(){
int T;
scanf("%d",&T);
while(T--){
map<PII,ll>tmpp;
ma.swap(tmpp);
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;i++){
sum_U[i]=sum_U[i-1];
sum_D[i]=sum_D[i-1];
sum_L[i]=sum_L[i-1];
sum_R[i]=sum_R[i-1];
if(s[i]=='U') sum_U[i]++;
else if(s[i]=='D') sum_D[i]++;
else if(s[i]=='L') sum_L[i]++;
else if(s[i]=='R') sum_R[i]++;
}
for(int i=1;i<=n;i++){
p[i].first=sum_R[i]-sum_L[i];
p[i].second=sum_U[i]-sum_D[i];
}
PII x;
x.first=x.second=0;
ma[x]++;
ll res=0;
for(int i=1;i<=n;i++){ // 枚举右端点
res+=ma[p[i]]; // 累加合法的左端点数目
ma[p[i]]++;
}
printf("%lld\n",res);
}
return 0;
}