A. Sherlock Bones
time limit per test1.5 s
memory limit per test256 MB
inputstandard input
outputstandard output
The great dog detective Sherlock Bones is on the verge of a new discovery. But for this problem, he needs the help of his most trusted advisor -you- to help him fetch the answer to this case.
He is given a string of zeros and ones and length N.
Let F(x, y) equal to the number of ones in the string between indices x and y inclusively.
Your task is to help Sherlock Bones find the number of ways to choose indices (i, j, k) such that i < j < k, sj is equal to 1, and F(i, j) is equal to F(j, k).
Input
The first line of input is T – the number of test cases.
The first line of each test case is an integer N (3 ≤ N ≤ 2 × 105).
The second line is a string of zeros and ones of length N.
Output
For each test case, output a line containing a single integer- the number of ways to choose indices (i, j, k).
Example
input
3
5
01010
6
101001
7
1101011
output
2
3
7
题意 : 给出一个 01 串,定义 F(i,j) 为 [i,j] 内 1 的个数,求满足 F(i,j) = F(j,k) (i < j < k) 且 s[j] == 1 的区间 (i,k) 的个数
思路 : 首先可以确定(i,k) 内 1 的个数一定为奇数个,可以预先处理出 1 ~ i 内 1 的奇偶数,然后再处理出 i ~ n 内(1 ~ i内1的奇偶数)的个数,然后倒着枚举 i, 1 ~ i 内有奇数个 1 ,者里该位置右边最近的 1 (因为 i ~ k 内至少有一个 1 )的位置以后的前面有偶数个 1 的位置都可做为 k ,偶数同理
AC代码 :
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX = 2e5 + 10;
typedef long long LL;
int p[MAX],o[2][MAX]; // o[0]([1])[i] 表示 i ~ n 有多少位置前面有偶(奇)数个 1
string s;
int main()
{
int T; scanf("%d",&T);
while(T--){
memset(p,0,sizeof(p)),memset(o,0,sizeof(o));
int n; cin >> n >> s;
for(int i = 0; i < n; i++) p[i + 1] = p[i] ^ (s[i] - '0');
int l = 0,r = 0;
for(int i = n; i >= 0; i--){
if(p[i]) r++; else l++;
o[0][i] = l,o[1][i] = r;
}
s = "0" + s; // 字符串变成 1 ~ n
int ok = 0,w;
LL ans = 0;
for(int i = n; i > 0; i--){
if(!ok){
if(s[i] == '1') ok = 1,w = i; // i ~ k 有奇数个 1
}
else{
if(p[i - 1]) ans += o[0][w + 1]; // 1 ~ i - 1 有奇数个 1, i ~ n 有多少位置前面有偶数个 1 ,这样 i ~ o 区间内就有奇数个 1 了,[i,j,k] 因为 k > j 所以第一个相邻的 1 不能包含在内
else ans += o[1][w + 1];
if(s[i] == '1') w = i;
}
}
printf("%lld\n",ans);
}
return 0;
}