101350A Sherlock Bones (思維+dp)
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
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
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;
}