【Gym - 101350A. Sherlock Bones】 & 思维

72 篇文章 1 订阅
14 篇文章 0 订阅

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值