题目:

现在有n个人,题目给出了他们每个人所在市县的编号。他们站在一个从左向右的队伍中。小L不在队列中。他想找到一个长度不超过D的区域,使他能够找到最多的不同地方的朋友。要求输出能找到的朋友所在不同市县的最大数和找到这些朋友的最小区间长度。比如在整个队伍内他按从左向右顺序找到了3个A地朋友,1个B地朋友,1个C地朋友。假设D=5,那么不同市县的最大数为3(A地、B地、C地),最小区间长度为3(只须结交A地的最右面的一个人即可得到最大市县数3,因此区间长度不是5而是3)。假设在队伍内的人他都还没有结交。

在这里写题解时,我总算是长吐了一口气。(因为vijos1000-1653的大部分数据我都有,而此题我没有数据,要是做错了话,是很难修改的)那么,我就把我一步步的想法写下来。

望到100万的数据,肯定是O(n)或是O(log(n)*n)。

后来还有一个最少人数的要求,很明显用最多人数的算法并二分答案。

然而我并不是天才,一开始是怎么也想不到最多人数算法,只是直接想到暴力枚举。(举报:HHD大神在我开始编之前就AK了!!!!)

      首先,我想到链表,而且不能用静态数组去代替。范围是n(100万)*k(32768),但实际上数据也就100万个。我本打算一个数组代表一个省份,里面记录该省份的人出现位置,根据同一数组里前后两个数位置进行操作(事实证明仍有点bug)。可是指针我真心不会,看了半天教程,还是云里雾里的。

      接着,我想到了之前想法的实际版(链表的不现实,因为我不会)。我们可以把人和位置快排(双关键字),再在每个省份内的人(此时已经连成一块了)里进行操作,同时加一点类似前缀和的优化。以下代码1即是这种实现。

      但是,我发现我样例也过不了,为什么呢?我猛然也发现了BUG。突然,我灵光一现,想到了一种真正的算法。由于打字麻烦,在这里引用HHD大神的题解(果然是英雄所见略同!):

先介绍下问题1的解法:

开一个4W的数组,刚开始置为0,表示该地区的大牛当前有几个,然后O(n)模拟。

先处理下1..d有几个不同的地区,然后每次把第一个去掉,然后后一个加上,即改成:2..d+1,然后3..d+2,最后n-d+1...n

每次去掉时,如果去掉后该地区的大牛没了,当前不同地区数就-1,每次加上时,如果加上后该地区大牛只有一个,那么不同地区数+1,每一轮加入删除后更新下答案,这样问题1O(N)搞定

long getans(long d)

{

if(d==0)return 0; long max=0;long now=0;for(longi=1;i<=39999;i++)temp[i]=0; for(long i=1;i<=d;i++) {temp[dl[i]]++;if(temp[dl[i]]==1)max++; }now=max; for(longi=d+1;i<=n;i++) { temp[dl[i-d]]--;if(temp[dl[i-d]]==0)now--;temp[dl[i]]++;if(temp[dl[i]]==1)now++; if(now>max)max=now;
}return max; }

问题2:我们可以发现,如果D越大,那么覆盖的不同地区肯定是严格递增的,而且D<1000000,所以可以二分,然后用上面的getans(d)来检验。时间效率O(nlogn)

 


但是,当我编好之后交上去,发现WA了两个点!(在代码二中标注)

仔细检查错误,我先把erfen(1,max)改成erfen(0,max),仍无济于事。

后来,我几乎绝望地初始化改成更大的(之前循环到n),没想到A了!

这说明,数据出的很不严谨,明明只有N个人,编号却有N+!

但我也要注意,以后做题时宁可更严谨些。



以下是代码:

代码一:

#include<stdio.h>
using namespace std;
long a[1000001],t,last,ans,ans2,i,max,n;
bool check(long k)
{
  long i;
  for (i=1;i<=n-k+1;i++)
    if (a[i+k-1]-a[i-1]==ans) returntrue;
  return false;
}
long erfen(long l,long r)
{
  long mid;
  mid=(l+r)/2;
  if (check(mid)) return erfen(l,mid);
  else return erfen(mid+1,r);
}
int main()
{
  scanf("%ld %ld",&n,&max);
  last=-1;
  for (i=1;i<=n;i++)
    {
      scanf("%ld",&t);
      if (t!=last)a[i]=a[i-1]+1;
      else a[i]=a[i-1];
      last=t;
    }
  for (i=1;i<=n-max+1;i++)
    if (a[i+max-1]-a[i-1]>ans)ans=a[i+max-1]-a[i-1];
  printf("%ld ",ans);
  ans2=erfen(1,max);
  printf("%ld",ans2);
  return 0;
}

代码二:

#include<stdio.h>
using namespace std;
longa[1000001],s[32769],t,last,ans,ans2,i,max,n,cnt;
bool check(long k)
{
  long i;cnt=0;
  for (i=1;i<=32768;i++)s[i]=0;//以前是i<=n
  for (i=1;i<=k;i++)
  {
    s[a[i]]++;if (s[a[i]]==1)cnt++;
  }
  if (cnt==ans) return true;
  for (i=k+1;i<=n;i++)
    {
      s[a[i]]++;if (s[a[i]]==1)cnt++;
      s[a[i-k]]--;if (s[a[i-k]]==0)cnt--;
      if (cnt==ans) returntrue;
    }
  return false;
}
long erfen(long l,long r)
{
  long mid;
  if (l==r) return l;
  mid=(l+r)/2;
  if (check(mid)) return erfen(l,mid);
  else return erfen(mid+1,r);
}
int main()
{
  scanf("%ld %ld",&n,&max);
  cnt=0;
  for (i=1;i<=n;i++)
    {
     scanf("%ld",&a[i]);
    }
  for (i=1;i<=32768;i++)s[i]=0;//以前是i<=n
  for (i=1;i<=max;i++)
  {
    s[a[i]]++;if (s[a[i]]==1)cnt++;
  }
  if (cnt>ans) ans=cnt;
  for (i=max+1;i<=n;i++)
    {
      s[a[i]]++;if (s[a[i]]==1)cnt++;
      s[a[i-max]]--;if (s[a[i-max]]==0)cnt--;
      if (cnt>ans)ans=cnt;
    }
  printf("%ld ",ans);
  ans2=erfen(0,max);//以前是(1,max)
  printf("%ld",ans2);
  //scanf("%ld",&ans);
  return 0;
}

vijos1760题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

随机推荐

  1. 《安卓网络编程》之第四篇 处理URL地址

    在Android手机系统中,可以通过URL地址获取网络资源.在URL类的众多方法中,可以使用openStream()方法来读取该URL资源的输入流InputStream.在此方法的基础上可以引申出很多 ...

  2. UITextField关闭自动联想功能

    在textField输入内容时,如果内容为英文,输入的英文如果不正确的单词就是有红色的线报警,关闭英文自动联想功能 self.autocorrectionType = UITextAutocorrec ...

  3. JS 一条原型链扯到底

    在正文之前,首先要知道两点, 1.__proto__是每个js 对象的内置属性,而prototype 是函数的内置属性,也是一个对象. 2.所谓原型,指的就是每个函数对象的prototype属性. f ...

  4. Mysql数据库二进制安装

    MySQL数据库有四种安装方法: 源码包编译安装 RPM包安装 二进制文件安装 官方yum源安装 这里我们主要介绍二进制包的安装方法 在MySQL官网下载二进制包并且上传到服务器上 解压二进制包 [r ...

  5. 每天一个JS 小demo之商品下架特效制作,主要知识点:定时器,倒计时,抖动特效。PS:由于不方便上传文件夹,只能上传效果图,图片等素材需自寻哟。

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  6. GPU编程-Thread Hierarchy(3)

    1. 如果处理的数据是二维的或者三维的,应该怎么办呢? 针对的,我们可以按照二维或者三维的方式,组织线程.老规矩,先代码.后解释 // Kernel definition __global__ voi ...

  7. Python爬虫-爬小说

    用途 用来爬小说网站的小说默认是这本御天邪神,虽然我并没有看小说,但是丝毫不妨碍我用爬虫来爬小说啊. 如果下载不到txt,那不如自己把txt爬下来好了. 功能 将小说取回,去除HTML标签 记录已爬过 ...

  8. php 多条件查询

    1.效果图如下: 点击提交后,把符合条件的筛选出来 2.代码: 逻辑:选中数据----以数组方式提交---拼接sql语句 难点: (1)从数据库里读取的数据要去重 (2)读取的数据是数组,要拼接 (3 ...

  9. Linux根目录各个文件夹介绍及说明

    /bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录的基点,比如用户user的主目录就是/home/use ...

  10. ORA-12638: 身份证明检索失败 解决方法

    用PL/SQL或Navicat连接本地或远程Oracle数据库的时候报错:ORA-12638: 身份证明检索失败 解决方法: 开始 -> 所有程序 -> Oracle - Oracle_h ...