计蒜客 T1853:非常男女(前缀和)

上一篇博客计蒜客 T1101:大整数的因子(高精度除法详解)

 写在前面:大家好!我是ACfun,我的昵称来自两个单词Acceptedfun。我是一个热爱ACM的蒟蒻。这篇博客来记录一下计蒜客T1853的解题思路。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油,冲鸭!
用知识改变命运,用知识成就未来!加油 (ง •̀o•́)ง (ง •̀o•́)ง

题目信息

原题链接:非常男女

题目描述

 近来,蒜头君致力于研究班上同学的配对问题(别想太多,仅是舞伴),通过各种推理和实验,他掌握了大量的实战经验。例如,据他观察,身高相近的人似乎比较合得来。

 万圣节来临之际,蒜头君准备在学校策划一次大型的“非常男女”配对活动。对于这次活动的参与者,蒜头君有自己独特的选择方式。他希望能选择男女人数相等且身高都很接近的一些人。这种选择方式实现起来很简单。他让学校的所有人按照身高排成一排,然后从中选出连续的若干个人,使得这些人中男女人数相等。为了使活动更热闹,蒜头君当然希望他能选出的人越多越好。请编写程序告诉他,他最多可以选出多少人来。

输入格式

 第一行有一个正整数 n (1 ≤ n ≤ 10^5),代表学校的人数。

 第二行有 n 个用空格隔开的数,这些数只能是 0 或 1,其中,0 代表一个女生,1代表一个男生。

输出格式

 输出一个非负整数,这个数表示在输入数据中最长的一段男女人数相等的连续子序列长度。

 输出时每行末尾的多余空格,不影响答案正确性

扫描二维码关注公众号,回复: 11450282 查看本文章

样例输入

9
0 1 0 0 0 1 1 0 0

样例输出

6

题解

解题思路

 在原数组中我们可以令男生为 1 ,女生为 -1。然后问题就转换为求一个最长子序列和为 0 的长度了。因为一个男生加一个女生和正好为零,这样只要找到两个位置的前缀和相等,他们之间就是男女相等的连续子序列。我们记录每个前缀和第一次出现的位置,下次出现的时候,减去第一次的位置就是长度。
 我们计算好所有的前缀和之后找出最长的男女相等的子序列即可。使用一个双重 for 循环来一次遍历每一个区间,求出每一个区间最长的长度,不断的更新这个最长的长度即可。这里要注意:前缀和都是从数组的第二个位置开始存储,也就是下标为 1 的位置开始存储,为了方便计算下标为 0 的位置都是 0 。第一个重循环来规定所求的区间长度,第二重循环来求该区间最长的子序列。只要找到相等就 break 直接求下一个区间长度的最大子序列,因为我们是从小到大开始遍历的所以在所求区间中第一次出现相等就代表最长的子序列,后面的长度就没有必要进行求了。(使用这个breakj极大的节省了运算时间,如果代码中没有这个break那么会直接超时。我实验了一下如果没有break那么运行时间会接近 2000ms ,而加上break运行时间直接缩短到 419ms。所以这个break操作也是至关重要的)

解题代码

#include<iostream>
using namespace std;

const int N = 1e5 + 10;
int n;
int per[N], s[N];

int main() {
    int max = 0;
    cin >> n;
    // 计算前缀和
    for (int i = 1; i <= n; i++) {
        scanf("%d", &per[i]);
        if (per[i] == 0) per[i] = -1;
        s[i] = s[i - 1] + per[i];
    }
    
    // 找出最长的男女人数相等的子序列
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < i; j++) {
            if (s[i] == s[j]) {
                if (i - j > max) {
                    max = i - j;
                }
                break;
            } 
        }
    }
    
    cout << max;
    
    return 0;
}

我是ACfun,感谢大家的支持!
冲鸭!

猜你喜欢

转载自blog.csdn.net/qq_41575507/article/details/107599559