ZR1001 欢乐 ABC(map 维护前缀和)

Description

求字符串 S S S 中有多少个子串,满足 A A A B B B C C C 出现次数相等。

1 ≤ ∣ S ∣ ≤ 1 0 6 1 \leq |S| \leq 10^6 1S106

Solution

若有 A A A B B B C C C 出现次数的前缀和。对于一个区间 [ l , r ] [l,r] [l,r],若满足下述条件,则合法。

A r − A l − 1 = B r − B l − 1 ⟹ A r − B r = A l − 1 − B l − 1 A_r - A_{l-1} = B_r - B_{l-1} \Longrightarrow A_r - B_r = A_{l-1}- B_{l-1} ArAl1=BrBl1ArBr=Al1Bl1

B r − B l − 1 = C r − C l − 1 ⟹ B r − C r = B l − 1 − C l − 1 B_r - B_{l-1} = C_r - C_{l-1} \Longrightarrow B_r - C_r = B_{l-1} - C_{l-1} BrBl1=CrCl1BrCr=Bl1Cl1

用 map 维护 ( A i − B i ,   B i − C i ) (A_i - B_i, \ B_i - C_i) (AiBi, BiCi) 的二元组即可,注意 ( 0 , 0 ) (0,0) (0,0) 应赋初值为 1 1 1

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int read() {
	int x = 0, f = 0; char ch = 0;
	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
	while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
	return f ? -x : x;
}
char s[N];
map < pair<int, int>, int> mp; 
int main(){
	scanf("%s", s);
	int n = strlen(s);
	int A = 0, B = 0, C = 0;
	ll ans = 0; 
	mp[make_pair(0, 0)] = 1;
	for (int i = 0; i < n; i++) {
		if (s[i] == 'A') A++;
		else if (s[i] == 'B') B++;
		else if (s[i] == 'C') C++;
		ans += mp[make_pair(A - B, B - C)]++;
	}
	printf("%lld\n", ans);
	return 0;
}
posted @ 2020-02-20 10:54  ylxmf2005  阅读(46)  评论(0)    收藏  举报