Promising String
[Link](Problem - F2 - Codeforces)
题意
给你一个字符串,当且仅当 + + +的数量等于 − - −的数量时称为好串,给你一个操作可以将任意两个相邻的 − - −变成一个 + + +,问你有多少个子串可以通过操作变成一个好串。
思路
对于任意一个子串若成立里需满足 c n t − − 2 × k = c n t + + k → c n t − − c n t + = 3 × k → c n t − − c n t + ≡ 0 ( m o d 3 ) cnt_- -2\times k=cnt_++k\to cnt_--cnt_+=3\times k \to cnt_--cnt_+ \equiv 0(mod\ 3) cnt−−2×k=cnt++k→cnt−−cnt+=3×k→cnt−−cnt+≡0(mod 3),设 s s s为原串的前缀和(原串 + + +为 − 1 -1 −1减为 1 1 1),则需要满足 s r − s l − 1 ≡ 0 ( m o d 3 ) s_r-s_{l-1}\equiv 0(mod\ 3) sr−sl−1≡0(mod 3),也就是对于任意一个位置 i i i找他前面有多少个位置满足上面的式子并且 s r ≥ s l − 1 s_r\ge s_{l-1} sr≥sl−1。
对于找某个数前面有多少个满足情况的位置,可以用树状数组动态统计,即开三个分别统计余数 0 , 1 , 2 0,1,2 0,1,2的情况,维护值域即可。
由于有负数,我们可以先离散化一下,然后再维护即可,或者直接同一加一个偏移量,保证所有的数都是大于 0 0 0的即可。
Code
- 离散化
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 2e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int op;
int tr[N][3];
int lowbit(int x) {
return x & -x;
}
void add(int x) {
for (; x <= m; x += lowbit(x)) tr[x][op] ++;
}
int sum(int x) {
int res = 0;
for (; x; x -= lowbit(x)) res += tr[x][op];
return res;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
cin >> n;
string str; cin >> str;
vector<int> s(n + 1);
vector<int> ve;
for (int i = 1; i <= n; i ++) s[i] = s[i - 1] + (str[i - 1] == '-' ? 1 : -1), ve.push_back(s[i]);
ve.push_back(0);
sort(ve.begin(), ve.end());
ve.erase(unique(ve.begin(), ve.end()), ve.end());
auto g = [&](int x) {
return lower_bound(ve.begin(), ve.end(), x) - ve.begin() + 1;
};
m = ve.size();
for (int i = 1; i <= m; i ++)
for (int j = 0; j < 3; j ++)
tr[i][j] = 0;
LL res = 0;
op = 0;
add(g(0));
for (int i = 1; i <= n; i ++) {
op = (s[i] % 3 + 3) % 3;
res += sum(g(s[i]));
add(g(s[i]));
}
cout << res << '\n';
}
return 0;
}
- 偏移量
#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 4e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int op;
int tr[N][3];
int lowbit(int x) {
return x & -x;
}
void add(int x) {
for (; x <= n * 2 + 1; x += lowbit(x)) tr[x][op] ++;
}
int sum(int x) {
int res = 0;
for (; x; x -= lowbit(x)) res += tr[x][op];
return res;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
int T;
cin >> T;
while (T -- ) {
string str;
cin >> n >> str;
vector<int> s(n + 1);
for (int i = 1; i <= n; i ++)
s[i] = s[i - 1] + (str[i - 1] == '-' ? 1 : -1);
for (int i = 1; i <= n * 2 + 1; i ++)
for (int j = 0; j < 3; j ++)
tr[i][j] = 0;
LL res = 0;
op = 0;
add(n + 1);
for (int i = 1; i <= n; i ++) {
op = (s[i] % 3 + 3) % 3;
res += sum(s[i] + n + 1);
add(s[i] + n + 1);
}
cout << res << '\n';
}
return 0;
}