[IOI2022] 最罕见的昆虫

题目描述

Pak Blangkon 的房子四周有 \(N\) 只昆虫,编号为 \(0\) 至 \(N-1\)。每只昆虫有一个类型,以从 \(0\) 至 \(10^9\)(包含 \(0\) 和 \(10^9\))的整数编号。可能有多只昆虫类型相同。

假设将昆虫按照类型分组。我们定义最常见昆虫类型的基数是昆虫最多的分组中的昆虫数。类似地,最罕见昆虫类型的基数是昆虫最少的分组中的昆虫数。

例如,假设有 \(11\) 只昆虫,类型分别为 \([5, 7, 9, 11, 11, 5, 0, 11, 9, 100, 9]\)。在此情形中,最常见昆虫类型的基数是 \(3\),是因为类型 \(9\) 和类型 \(11\) 的分组均有最多数目的昆虫,每个分组都有 \(3\) 只。最罕见昆虫类型的基数是 \(1\),是因为类型 \(7\)、类型 \(0\) 和类型 \(100\) 的分组均有最少数目的昆虫,每个分组都有 \(1\) 只。

Pak Blangkon 不知道这些昆虫的类型。他有一台单按钮的机器,可以提供昆虫类型相关的信息。刚开始时,机器是空的。在使用机器时,可以做如下三种操作:

  1. 将一只昆虫放进机器。
  2. 将一只昆虫取出机器。
  3. 按下机器的按钮。

每种操作最多可以做 \(40\;000\) 次。

每当按下按钮时,机器会报告在机器内的最常见昆虫类型的基数。

你的任务是使用上述机器,确定 Pak Blangkon 的房子四周所有 \(N\) 只昆虫中最罕见昆虫类型的基数。此外,在某些子任务里,你的得分取决于机器执行某种操作的最大次数(详见子任务一节)。

输入格式

你要实现以下函数:

int min_cardinality(int N)
  • \(N\):昆虫数量。
  • 此函数应返回 Pak Blangkon 的房子四周所有 \(N\) 只昆虫中最罕见昆虫类型的基数。
  • 此函数恰好被调用一次。

该函数可调用以下几个函数:

void move_inside(int i)
  • \(i\):将被放进机器的昆虫编号。编号 \(i\) 的取值范围是 \(0\) 至 \(N-1\)(包含 \(0\) 和 \(N-1\))。
  • 如果昆虫已在机器内,函数调用不会影响机器内昆虫的集合。但是,调用仍会被计入此类操作的次数。
  • 此函数最多可以被调用 \(40\;000\) 次。
void move_outside(int i)
  • \(i\):将被从机器中取出的昆虫编号。编号 \(i\) 的取值范围是 \(0\) 至 \(N-1\)(包含 \(0\) 和 \(N-1\))。
  • 如果昆虫已在机器外,函数调用不会影响机器内昆虫的集合。但是,调用仍会被计入此类操作的次数。
  • 此函数最多可以被调用 \(40\;000\) 次。
int press_button()
  • 此函数返回机器内最常见昆虫类型的基数。
  • 此函数最多可以被调用 \(40\;000\) 次。
  • 评测程序不是适应性的。也就是说,所有 \(N\) 只昆虫的类型在 min_cardinality 调用前已经确定。

输出格式

考虑在某个场景下,有 \(6\) 只类型分别为 \([5, 8, 9, 5, 9, 9]\) 的昆虫。

函数 min_cardinality 的调用方式如下:

min_cardinality(6)

此函数按以下次序调用了 move_insidemove_outsidepress_button

函数调用 返回值 机器内的昆虫 机器内的昆虫类型
\(\\{\\}\) \([\ ]\)
move_inside(0) \(\\{0\\}\) \([5]\)
press_button() \(1\) \(\\{0\\}\) \([5]\)
move_inside(1) \(\\{0, 1\\}\) \([5, 8]\)
press_button() \(1\) \(\\{0, 1\\}\) \([5, 8]\)
move_inside(3) \(\\{0, 1, 3\\}\) \([5, 8, 5]\)
press_button() \(2\) \(\\{0, 1, 3\\}\) \([5, 8, 5]\)
move_inside(2) \(\\{0, 1, 2, 3\\}\) \([5, 8, 9, 5]\)
move_inside(4) \(\\{0, 1, 2, 3, 4\\}\) \([5, 8, 9, 5, 9]\)
move_inside(5) \(\\{0, 1, 2, 3, 4, 5\\}\) \([5, 8, 9, 5, 9, 9]\)
press_button() \(3\) \(\\{0, 1, 2, 3, 4, 5\\}\) \([5, 8, 9, 5, 9, 9]\)
move_inside(5) \(\\{0, 1, 2, 3, 4, 5\\}\) \([5, 8, 9, 5, 9, 9]\)
press_button() \(3\) \(\\{0, 1, 2, 3, 4, 5\\}\) \([5, 8, 9, 5, 9, 9]\)
move_outside(5) \(\\{0, 1, 2, 3, 4\\}\) \([5, 8, 9, 5, 9]\)
press_button() \(2\) \(\\{0, 1, 2, 3, 4\\}\) \([5, 8, 9, 5, 9]\)

至此,已有充分信息表明,最罕见昆虫类型的基数是 \(1\)。

因此,函数 min_cardinality 应返回 \(1\)。

在这个例子里,move_inside 被调用 \(7\) 次,move_outside 被调用 \(1\) 次,press_button 被调用 \(6\) 次。

提示

约束条件

  • \(2 \le N \le 2000\)。

子任务

  1. (10 分) \(N \le 200\);
  2. (15 分) \(N \le 1000\);
  3. (75 分) 没有额外的约束条件。

如果在某个测试用例上,函数 move_insidemove_outsidepress_button 的调用次数不符合“实现细节”中给出的约束条件,或者 min_cardinality 的返回值不正确,你的解答在此子任务上得分为 \(0\)。

令 \(q\) 为以下三个值的 最大值move_inside 的调用次数、move_outside 的调用次数、press_button 的调用次数。

在子任务 3 中,你可能会得部分分。令 \(m\) 为此子任务所有测试用例的 \(\frac{q}{N}\) 的最大值。你在此子任务的得分将根据以下表格计算:

条件 得分
\(20 \lt m\) \(0\) (CMS 报告“Output isn’t correct”)
\(6 \lt m \le 20\) \(\frac{225}{m - 2}\)
\(3 \lt m \le 6\) \(81 - \frac{2}{3} m^2\)
\(m \le 3\) \(75\)

评测程序示例

令 \(T\) 是长度为 \(N\) 的整数数组,其中 \(T[i]\) 是编号为 \(i\) 的昆虫的类型。

评测程序示例按以下格式读取输入:

  • 第 \(1\) 行:\(N\);
  • 第 \(2\) 行:\(T[0] \; T[1] \; \ldots \; T[N - 1]\)。

如果评测程序示例检测到非法行为,评测程序示例将输出 Protocol Violation: <MSG>,其中 <MSG> 为如下某种类型:

  • invalid parameter:在函数调用 move_insidemove_outside 时,参数 \(i\) 的值不在 \(0\) 至 \(N-1\) 的范围内(包括 \(0\) 和 \(N-1\))。
  • too many calls:函数 move_insidemove_outsidepress_button某个的调用次数超过 \(40\;000\) 次。

否则,评测程序示例按以下格式输出:

  • 第 \(1\) 行:min_cardinality 的返回值;
  • 第 \(2\) 行:\(q\)。

约定

题面在给出函数接口时,会使用一般性的类型名称 voidboolintint[](数组)和 union(bool, int[])

在 C++ 中,评测程序会采用适当的数据类型或实现,如下表所示:

void bool int int[]
void bool int std::vector<int>
union(bool, int[]) 数组 a 的长度
std::variant<bool, std::vector<int>> a.size()

C++ 语言里,std::variant 定义在 <variant> 头文件中。

一个返回类型为 std::variant<bool, std::vector<int>> 的函数可以返回一个 bool 或一个 std::vector<int>

以下示例代码给出了三个返回 std::variant 的函数,它们都能正常工作:

std::variant<bool, std::vector<int>> foo(int N) {
return N % 2 == 0;
} std::variant<bool, std::vector<int>> goo(int N) {
return std::vector<int>(N, 0);
} std::variant<bool, std::vector<int>> hoo(int N) {
if (N % 2 == 0) {
return false;
} return std::vector<int>(N, 0);
}

只考了二分的IOI非送分题。

告诉你的是最大值,要求的是最小值,不难想到二分。

现在二分出来最小值是 \(md\),那么想象不断往机器里放数,如果众数数量大于 \(md\),那就把刚刚放的数拿出来。

把所有数这样子跑一次以后,如果最终机器里有 \(c\) 个数,那么想象当 \(md\) 小于等于最终答案时,\(c\) 为多少?

如果有 \(cnt\) 个种类,那么每一个种类都有多于 \(md\) 个数。所以\(c=md\times cnt\)。判定一下就可以了。操作次数大概 \(2nlogn\),有点分了。至于怎么求 \(cnt\),可以控制机器中众数数量为1,放入昆虫后如果大于1就拿出来,然后最后看昆虫数量就行了

那么考虑优化。发现如果此时判定出来 \(md\) 小于等于最终答案,此时已经在机器中的数就不用再拿出来了。同理,如果最终 \(md\) 大于最终答案,不在机器中的数就永远不用放进去了。可以打个标记。这样子大约是 \(n+\frac n2+\frac n4+\cdots\),加上求 \(cnt\) 的复杂度,共 \(3n\)。

但是他不是严格的把总数除以2?而且交上去竟然只有99分。由于交互库不自适应,不需要真的把总数除以2,只要期望除2就行了。所以这99分可以卡一下。发现如果此时在机器中的数已经达到 \(cnt\times md\) 个,就可以直接 break 了。然后把放入昆虫的顺序随机打乱一下,就可以过了。

注意二分区间右端点初始化要设成 \(\frac{n}{cnt}\),不然会被轻松卡飞的。

#include<bits/stdc++.h>
using namespace std;
int n,cnt,ret,vs[2005],vs1[2005],id[2005],now,l,r;
void move_inside(int i);
void move_outside(int i);
int press_button();
void add(int x)
{
vs[x]=1,++ret;
move_inside(x-1);
}
void del(int x)
{
vs[x]=0,--ret;
move_outside(x-1);
}
int min_cardinality(int n) {
srand(time(0));
for(int i=1;i<=n;i++)
{
add(id[i]=i);
if(press_button()>1)
del(i);
else
++cnt;
}
for(int i=1;i<=n;i++)
if(vs[i])
del(i);
r=n/cnt;
// printf("xzdakioi:%d\n",ret);
while(l<=r)
{
int md=l+r>>1;
// printf("crxzdq:%d %d\n",l,r);
random_shuffle(id+1,id+n+1);
for(int i=1;i<=n;i++)
{
if(!vs[id[i]]&&!vs1[id[i]])
{
add(id[i]);
if(press_button()>md)
del(id[i]);
}
if(ret==cnt*md)
break;
}
// printf("cjhyyds:%d\n",ret);
// for(int i=1;i<=n;i++)
// printf("%d %d\n",vs1[i],vs[i]);
// puts("");
if(ret==cnt*md)
{
for(int i=1;i<=n;i++)
if(vs[id[i]])
vs1[id[i]]=1;
l=md+1;
}
else
{
for(int i=1;i<=n;i++)
{
if(!vs[id[i]])
vs1[id[i]]=1;
else if(!vs1[id[i]])
del(id[i]);
}
r=md-1;
}
}
return r;
}

[洛谷P8494] [IOI2022] 最罕见的昆虫的更多相关文章

  1. 洛谷P5069 [Ynoi2015]纵使日薄西山(树状数组,set)

    洛谷题目传送门 一血祭 向dllxl致敬! 算是YNOI中比较清新的吧,毕竟代码只有1.25k. 首先我们对着题意模拟,寻找一些思路. 每次选了一个最大的数后,它和它周围两个数都要减一.这样无论如何, ...

  2. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  3. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  4. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  5. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  6. 洛谷P1710 地铁涨价

    P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交  讨论  题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...

  7. 洛谷P1371 NOI元丹

    P1371 NOI元丹 71通过 394提交 题目提供者洛谷OnlineJudge 标签云端评测 难度普及/提高- 提交  讨论  题解 最新讨论 我觉得不需要讨论O long long 不够 没有取 ...

  8. 洛谷P1538迎春舞会之数字舞蹈

    题目背景 HNSDFZ的同学们为了庆祝春节,准备排练一场舞会. 题目描述 在越来越讲究合作的时代,人们注意的更多的不是个人物的舞姿,而是集体的排列. 为了配合每年的倒计时,同学们决定排出——“数字舞蹈 ...

  9. 洛谷八月月赛Round1凄惨记

    个人背景: 上午9:30放学,然后因为学校举办读书工程跟同学去书城选书,中午回来开始打比赛,下午又回老家,中间抽出一点时间调代码,回家已经8:50了 也许是7月月赛时“连蒙带骗”AK的太幸运然而因同学 ...

  10. 洛谷 P1379 八数码难题 Label:判重&&bfs

    特别声明:紫书上抄来的代码,详见P198 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给 ...

随机推荐

  1. Flutter系列文章-Flutter应用优化

    当涉及到优化 Flutter 应用时,考虑性能.UI 渲染和内存管理是至关重要的.在本篇文章中,我们将通过实例深入讨论这些主题,展示如何通过优化技巧改进你的 Flutter 应用. 代码性能优化 1. ...

  2. ImGui界面优化:使用图标字体、隐藏主窗口标题栏

    目录 使用图标字体 扩展:内存加载字体 隐藏主窗口标题栏 增加程序退出 改进HideTabBar 窗口最大化 总结 本文主要介绍ImGui应用中的一些界面优化方法,如果是第一次使用ImGui推荐从上一 ...

  3. Vmware中的centos7突然连接不上网络了,网络适配器采用的是NAT模式,解决办法?

    进入Windows操作系统,然后右键点击我们的电脑,进入到管理界面 计算机-> 管理->服务和应用程序->服务,找到如下服务进程 VMware DHCP Service, VMwar ...

  4. pygame 入门实例教程 1 - 复古方块赛车游戏

    作者自我介绍:大爽歌, b站小UP主 ,直播编程+红警三 ,python1对1辅导老师 . 本教程步骤明确,过程清晰简明,最终代码量250行上下,适合学习pygame的新手. 项目代码已上传到我的gi ...

  5. MindSpore简要性能分析

    技术背景 在之前的一篇博客中,我们介绍过MindInsight的安装与使用.不过在前面的文章中,我们主要介绍的是MindInsight与SummaryCollector的配合使用,更多的是用于对结果进 ...

  6. 例子:统计电影类型的个数,以及用bar绘制出来表示

    import pandas as pdimport numpy as npfrom matplotlib import pyplot as plt#获取各种电影类型的数量file='./IMDB-Mo ...

  7. SQL Server用户的设置与授权

    SQL Server用户的设置与授权 SSMS 登陆方式有两种,一是直接使用Windows身份验证,二是SQL Server身份验证.使用SQL Server用户设置与授权不仅可以将不同的数据库开放给 ...

  8. 【遥遥领先】Eolink IDEA 插件:零代码入侵,自动生成接口

    省流版: Eolink 有 IDEA 插件吗? 有,而且遥遥领先!我们在一年半之前就发布了,而且功能更丰富! IDEA 插件市场搜索"Eolink Apikit"即可安装使用. 使 ...

  9. os --- 多种操作系统接口¶

    os.path --- 常用路径操作 源代码: Lib/posixpath.py (用于 POSIX) 和 Lib/ntpath.py (用于 Windows). 此模块实现了一些有用的路径名称相关函 ...

  10. MySQL误删恢复方法1

    MySQL不同于oracle,没有闪回查询这类概念,但网上流传几个闪回的开源工具如 binglog2sql.MyFlash,可以使用binglog日志进行误操作数据的恢复. 笔者以前测试过 bingl ...