【题目】洛谷P1114 “非常男女”计划

【题目】洛谷P1114 “非常男女”计划

一道关于前缀和妙用的题目。

题目描述

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

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

输入输出格式

输入格式:

第一行有一个正整数n,代表学校的人数。n<=100000。

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

输出格式:

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

如果不存在男女人数相等的子序列,请输出0。

输入输出样例

输入样例#1:

9
0 1 0 0 0 1 1 0 0

输出样例#1:

6

思路

引入相对差的概念。即a[i]表示第i个位置男生人数-女生人数的差值。

那么差值相等的两个位置之间的人数是满足男女相等的。

核心思想仍然是前缀和标准差,当读到男生时+1,读到女生时-1,维护一个前缀和,当前缀和相等时即为出现男女人数相等的子序列。

不一样的是查找最长序列的方式,笔者先将前缀和按升序排序,这样就可以轻松把前缀和相同的区间凑到一起;统计每一个前缀和相同的区间长度,利用双指针区间扫描找最大值即可。这当然没有dalao们程序快,不过时间复杂度还是允许的,详情请见代码。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<cmath>
#define by Mashiro_ylb
#define TIME 2017/10/28
using namespace std;
const int max_data = 100007;

struct node
{
    int data;  //记录前缀和大小
    int cnt;  //记录出现位置
}a[max_data];
int n;

template<class T>void read(T &x) //读入优化
{
    int f = 0; x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') f |= (ch == '-'), ch = getchar();
    while(ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    x = f? -x : x;
}
template<class T>void write(T x) //输出优化
{
    if(x < 0) x = -x, putchar('-');
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
}
template<class T>T Max(T x, T y){return x > y? x : y;}
bool cmp(const node &x, const node &y){return x.data == y.data? (x.cnt < y.cnt) : (x.data < y.data);} //先按照前缀和升序排序,若相等则按照出现位置升序排序
void init();
int work();

int main()
{
//    freopen("in.txt","r",stdin);
    init();
    write(work());
    return 0;
}

void init()
{
    read(n);
    int x;
    for(int i = 1; i <= n; i++)
      {
          read(x);
          a[i].data = a[i - 1].data + (x? 1 : -1);  //前缀求和
          a[i].cnt = i;  //记录出现位置
      }
}

int work()
{
    int maxn = 0;  //记录最大值
    sort(a + 0, a + n + 1, cmp);  //排序(注意从0开始而不是1)
    int z1 = 0, z2 = 1;  //设立双指针
    while(z2 <= n)  //区间扫描
      {
          if(a[z1].data == a[z2].data)  //查找最大区间
            {
                  z2++;
                  continue;
          }
        else
          {
              maxn = Max(maxn, a[z2 - 1].cnt - a[z1].cnt);  //记录
              z1 = z2;
          }
      }
    return maxn;
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/Mashiro_ylb/article/details/78380786