洛谷1114 “非常男女”计划

本题地址:http://www.luogu.org/problem/show?pid=1114

题目描述

  近来,初一年的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

思路分析:

(1) 最简单的想法就是遍历所有的子串,之后判断该子串是否满足条件。(就像寻找最大子序列一样。)有 N^2子串,每个子串扫一遍判断0、1是否出现的次数相等,复杂度为O(N^3)。

进一步思考就会发现, 如果一个长度为n的子串满足条件,加么这n个元素的和 加起来一定=(n/2),这样在循环的过程中,增量加就可以了,不需要每个子串从头计算,复杂度降为O(N^2)。

(嗯,这个地方的改进其实就是最大子序列和问题当中O(N^2)级别算法的类似改进。)

最大子序列和问题:http://www.cnblogs.com/huashanqingzhu/p/3861238.html

上述解决最大子序列和问题的两个算法:(下面三张图片截取自浙大陈越老师的PPT)

(2)为了进一步降低算法的时间复杂度,引入相对差的概念。即a[i]表示第i个位置男生人数-女生人数的差值。
那么差值相等的两个位置之间的人数是满足男女相等的。因此,统计l[a[i]]和r[a[i]]即可。特别要注意的是a[0]=0。
统计的时候要把0的位置当做差为0的起点。
上述这段话是原题目网站的提示,思考半天,没太理解。
(试想:在含有n个元素的整数序列中寻找两个距离最远而且相等的元素,时间复杂度似乎也是平方级别的。)
后来看到网络上有人对这个题的类似题目做了一个简单的解析:
http://www.cnblogs.com/worldisimple/archive/2012/04/13/2445051.html
摘抄原文部分:

一个01字符串,求出现0、1出现次数相等的最长子串

题目描述:

已知一个长度为N的字符串,只由0和1组成, 求一个最长的子串,要求该子串出0和1出现的次数相等。

要求算法时间复杂度尽可能的低。

比如:  1000010111000001,加粗的部分有4个0、4个1

原文作者对此给出的比较好的解决思路:

定义一个数据B[N], B[i]表示从A[0...i]中 num_of_0 - num_of_1,0的个数与1的个数的差

那么如果A[i] ~ A[j]是符合条件的子串,一定有 B[i] == B[j],因为中间的部分0、1个数相等,相减等于0。 只需要扫一遍A[N]就能把B[N]构造出来了。

这样问题就转换成了求 距离最远的一对数,使得B[i] == B[j],因为B[i]的范围一定是[-N,N],-N到N的范围都存起来,这样每扫到B[i],查数就行了。

 int A[N],B[N];
int num[*N + ];
int count[] = {,}, maxlen = , currlen = ;
memset(C, *N, -);
for(int i = ; i < N; ++i)
{
count[ int(A[i]) ] += ;
B[i] = count[] - count[];
if( num[ B[i] + N ] == -)//尚不存在,B的下标是差,值是A的下标
num[ B[i] + N ] = i;
else//already exist
{
currlen = i - num[ B[i] + N ] + ; //num[ B[i] + N ]是B[i]已存在的下标
if(currlen > maxlen)
maxlen = currlen;
}
对于原文作者伪代码的错误和不严谨,我就不说了。
重要的是,看了分析,大概明白了如何用O(n)的时间复杂度完成“在含有n个元素的整数序列中寻找两个距离最远而且相等的元素”这样一个问题。
但是,该文章的作者没注意到:统计的时候要把0的位置当做差为0的起点。修改了文章作者的代码,得到如下的AC代码:
 #include <stdio.h>
#include<stdlib.h>
int main()
{
int n,t;
int *b,*num;
int count[]={,};//统计从第一个到第i个位置的子段中,0和1的个数
int maxlen=,currlen=;
int i;
scanf("%d",&n);
b=(int *)malloc((n+)*sizeof(int));
num=(int *)malloc((n*+1)*sizeof(int));
for(i=;i<=n;i++)
b[i]=; //b[i]用于记录0-1序列的前i个值中,0和1的个数之差
for(i=;i<=*n+;i++)
num[i]=-; //num[]用于统计记录b[]各元素首次出现的下标。比如b[i]==x,而且i是x在b[]首次出现的位置,则num[b[i]+n]=i。num[i]默认值-1. for(i=;i<=n;i++)
{
scanf("%d",&t); //输入一个数字:0或1
count[t]++; //统计0和1的个数
b[i]=count[]-count[];//b[i]保存0-1序列的前i个元素中:0和1的个数之差
}
if(count[]==count[]) printf("%d\n",count[]+count[]);
else
{
for(i=;i<=n;i++)//注意:从0和1的个数都是0的地方开始扫描
{
if(num[b[i]+n]==-) //检测b[i]的值是否曾经在b[]出现过。num[b[i]+n]== -1表示b[i]没有出现过
num[b[i]+n]=i; //记录b[i]的值在b[]首次出现的位置i
else//already exist
{
currlen = i - num[b[i]+n] ; //num[b[i]+n]是b[i]首次出现的下标
if(currlen > maxlen)
maxlen = currlen;
}
}
printf("%d\n",maxlen);
} free(b);
free(num);
return ;
}
												

[洛谷OJ] P1114 “非常男女”计划的更多相关文章

  1. USACO Section 1.3 题解 (洛谷OJ P1209 P1444 P3650 P2693)

    usaco ch1.4 sort(d , d + c, [](int a, int b) -> bool { return a > b; }); 生成与过滤 generator&& ...

  2. Luogu P1114 “非常男女”计划/Luogu P2697 宝石串

    Luogu P1114 "非常男女"计划/Luogu P2697 宝石串 (感觉我最近很爱做双倍经验的题啊) 使$d$等于第$i$个位置男生数(绿宝石数)减女生数(红宝石数)的差值 ...

  3. 洛谷 P1114 “非常男女”计划

    To 洛谷.1114 “非常男女”计划 题目描述 近来,初一年的XXX小朋友致力于研究班上同学的配对问题(别想太多,仅是舞伴),通过各种推理和实验,他掌握了大量的实战经验.例如,据他观察,身高相近的人 ...

  4. BZOJ1229 & 洛谷2917:[USACO2008 NOV]toy 玩具 & 洛谷4480:[BJWC2018]餐巾计划问题——题解

    标题很长emmm…… [USACO2008 NOV]toy 玩具 https://www.luogu.org/problemnew/show/P2917 https://www.lydsy.com/J ...

  5. 洛谷——P1089 津津的储蓄计划

    https://www.luogu.org/problem/show?pid=1089 https://www.luogu.org/problem/show?pid=1089 题目描述 津津的零花钱一 ...

  6. 洛谷P1089 津津的储蓄计划

    题目描述 津津的零花钱一直都是自己管理.每个月的月初妈妈给津津300元钱,津津会预算这个月的花销,并且总能做到实际花销和预算的相同. 为了让津津学习如何储蓄,妈妈提出,津津可以随时把整百的钱存在她那里 ...

  7. 洛谷OJ P1196 银河英雄传说(带权并查集)

    题目描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦 创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山 ...

  8. 【BZOJ2595_洛谷4294】[WC2008]游览计划(斯坦纳树_状压DP)

    上个月写的题qwq--突然想写篇博客 题目: 洛谷4294 分析: 斯坦纳树模板题. 简单来说,斯坦纳树问题就是给定一张有边权(或点权)的无向图,要求选若干条边使图中一些选定的点连通(可以经过其他点) ...

  9. [洛谷P1114] “非常男女”计划

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

随机推荐

  1. MFC编程入门之十三(对话框:属性页对话框及相关类的介绍)

    前面讲了模态对话框和非模态对话框,本节来将一种特殊的对话框--属性页对话框. 属性页对话框的分类 属性页对话框想必大家并不陌生,XP系统中桌面右键点属性,弹出的就是属性页对话框,它通过标签切换各个页面 ...

  2. YUV格式&像素

    一幅彩色图像的基本要素是什么? 说白了,一幅图像包括的基本东西就是二进制数据,其容量大小实质即为二进制数据的多少.一幅1920x1080像素的YUV422的图像,大小是1920X1080X2=4147 ...

  3. "编写高质量代码"一书笔记

    总结 css架构结构 :       base  :   共用样式   common: 通用控件样式   page: 页面级样式   js 架构结构:   base 位于三层最底层,职责一是封装不同浏 ...

  4. SSM框架学习之高并发秒杀业务--笔记4-- web层

    在前面几节中已经完成了service层和dao层,到目前为止只是后端的设计与编写,这节就要设计到前端的设计了.下面开始总结下这个秒杀业务前端有哪些要点: 1. 前端页面的流程 首先是列表页,点某个商品 ...

  5. guava--Joiner、Splitter、MapJoinner、MapSplitter

    Joiner: List<String> stringList = new ArrayList<String>(); stringList.add("aa" ...

  6. MongoDB搭建Replica Set Shard Cluster步骤

    本文记录从头搭建一个MongoDB 副本集分片集群的过程. 我们要创建一个这样子的分布式集群:有两个shard,每个shard都是一个replica set,各有两个副本(实际产品应用中还应加上一个仅 ...

  7. Discuz升级提示static/image/postbg/3.jpg下载出现问题的解决办法

    discuz2.5升级3.0的时候出现错误.提示static/image/postbg/3.jpg下载出现问题,其解决办法如下 找到 source/admincp/admincp_upgrade.ph ...

  8. 斯诺登称NSA攻破互联网加密技术

    据财新网报道,本已渐渐平静的斯诺登泄密事件在9月6日再掀波澜.英国<卫报>.美国<纽约时报>和美国非盈利调查新闻机构ProPublica联合报道称,根据斯诺登提供的大量文件,美 ...

  9. ROS 使用自带和usb摄像头获取图像

    笔记本自带的摄像头的设备号一般为/dev/video0 第一步:安装Webcam 驱动 $ sudo apt-get install git-core $ cd ~/catkin_ws/src $ g ...

  10. IDE启动报错

    启动IDE的时候报出org.eclipse.swt.SWTException: Invalid thread access解决方法:退出再次启动IDE的时候加上-clean选项,如图中所示,前面是我的 ...