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 yinclusively.
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串s,让你找出三个下标i,j,k,使得从i到j的1的个数等于从j到k的1的个数,并且s[j]=1,问有多少种这样的i,j,k。
解法:满足这样的条件的i,j,k,其从i到k的1的个数必定为奇数,因此可以先求出1的个数为奇的区间个数,然后排除一些非法的区间如1,001,100等,即可得到答案。
我们设d[i][j]表示以下标i为左端点并且1的个数为奇或偶的个数(0表示偶,1表示奇),则由d[i-1][j]可以直接得到d[i][j],因此可以在O(n)的时间内求出1的个数为奇数的区间个数,然后减去非法区间的个数即可。
注意全部为0的时候要特判一下,而且要用long long来保存答案。
#define FRER() freopen("i.txt","r",stdin)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=2e5+10;
int n;
char s[N];
int d[N][2];
int idx(char ch)
{
return ch^48;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(d,0,sizeof d);
scanf("%d%s",&n,s);
int x=0;
for(int j=0; j<n; ++j)
{
x^=idx(s[j]);
++d[0][x&1];
}
for(int i=1; i<n; ++i)
{
d[i][0]=d[i-1][0];
d[i][1]=d[i-1][1];
if(s[i-1]=='0')--d[i][0];
else --d[i][1];
if(s[i-1]=='1')swap(d[i][0],d[i][1]);
}
ll ans=0;
for(int i=0; i<n; ++i)ans+=d[i][1];
if(ans!=0)
{
int L=0,R=n-1;
while(L<n&&s[L]=='0')++L,--ans;
while(R>=0&&s[R]=='0')--R,--ans;
for(int i=L; i<=R; ++i)
{
if(s[i]=='0')ans-=2;
else ans-=1;
}
}
printf("%lld\n",ans);
}
return 0;
}
滚动数组写法:
#define FRER() freopen("i.txt","r",stdin)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=2e5+10;
int n;
char s[N];
int d[2][2];
int idx(char ch)
{
return ch^48;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(d,0,sizeof d);
ll ans=0;
scanf("%d%s",&n,s);
int x=0;
for(int j=0; j<n; ++j)
{
x^=idx(s[j]);
++d[0][x&1];
}
ans+=d[0][1];
for(int i=1; i<n; ++i)
{
d[i&1][0]=d[(i^1)&1][0];
d[i&1][1]=d[(i^1)&1][1];
if(s[i-1]=='0')--d[i&1][0];
else --d[i&1][1];
if(s[i-1]=='1')swap(d[i&1][0],d[i&1][1]);
ans+=d[i&1][1];
}
if(ans!=0)
{
int L=0,R=n-1;
while(L<n&&s[L]=='0')++L,--ans;
while(R>=0&&s[R]=='0')--R,--ans;
for(int i=L; i<=R; ++i)
{
if(s[i]=='0')ans-=2;
else ans-=1;
}
}
printf("%lld\n",ans);
}
return 0;
}