题解:[NOIP2016 提高组] 蚯蚓
前置结论
结论
对于整数 $x_1,x_2$ ,当 $x_1\geq x_2,0<p<1$ 时有:
- $\lfloor px_1 \rfloor \geq \lfloor px_2 \rfloor$
- $x_1 -\lfloor px_1 \rfloor \geq x_2- \lfloor px_1 \rfloor$
证明
结论 $1$ 显然得证。
结论 $2$ 证明参见此处。以下为转载内容。
2024 年 7 月更新:新版蓝书受我反馈,已经更正此问题。
本题中所有题解的单调性正确性似乎都有或多或少的问题,在这里我给出一个严谨的单调性证明。
首先:$x - \lfloor px \rfloor$ 这个函数并不是单调不降的,它只在整点上单调不降,可以在 desmos 中画一个 $x - \lfloor 0.9x \rfloor$ 的函数试试看,你会发现它并没有单调性。当然,$x - px$ 有单调性。
所以一切直接抛开下取整对单调性的证明是没有任何道理的,这就叉掉了本题大量题解,包括但不限于第一篇题解。
同时,一切没有用到 $x_1$,$x_2$ 这两个数为整数这个性质就证出了这个函数的单调性的都是伪证,本题疑似所有题解全都是伪证。lyd 蓝书上的证明也是伪证,具体原因见下。
前置知识:
- 下取整函数单调不降,即对于 $x_1 < x_2$ 有 $\lfloor x_1\rfloor \le \lfloor x_2 \rfloor$;
- 整数可以自由移入移出下取整函数,即对于 $z \in \mathbb Z$,有 $\lfloor x \rfloor + z = \lfloor x + z \rfloor$。
- 注意:负号不能随便移入移出,$\lfloor -3.4 \rfloor \ne - \lfloor 3.4 \rfloor$。
- 关于这点很容易犯的一个错误就是对于 $z \in \mathbb Z$,有$\lfloor z - x \rfloor = z - \lfloor x \rfloor$,事实上这点根本不成立,举个反例:$\lfloor 1 - 0.3 \rfloor \ne 1 - \lfloor 0.3\rfloor$。
- 刚刚这条错误就是很多伪证的错误原因所在,包括 lyd 蓝书的证明也存在这个伪证。
真正证明:
命题:对于 $x_1, x_2 \in \mathbb Z, x_1 \ge x_2, 0< p < 1$,有 $x_1 - \lfloor px_1 \rfloor \ge x_2 - \lfloor px_2 \rfloor$。
证明:$x_1 \ge x_2 \land x_1, x_2 \in \mathbb Z$,因此 $x_1 - x_2 \in \mathbb N$。又因为 $0 <p < 1$,所以:
$$
\begin{aligned}
x_1 - x_2 &\ge p(x_1 - x_2)\
x_1 - x_2 + p x_2 & \ge px_1 \
\lfloor px_2 + (x_1 - x_2) \rfloor & \ge\lfloor px_1 \rfloor \
\lfloor px_2 \rfloor + (x_1 - x_2) & \ge \lfloor px_1 \rfloor \
x_1 - \lfloor px_1 \rfloor & \ge x_2 - \lfloor px_2 \rfloor
\end{aligned}
$$证明出了这一点的单调性之后,事实上我们就解决了 $q = 0$ 的单调性问题,接下来解决 $q \ge 0$ 的。
我们假设某一秒,我们切开了一个数 $x_1$,下一秒,我们切开了一个数 $x_2 + q$。$x_2 + q$ 在上一秒时为 $x_2$,因此 $x_1 \ge x_2$。我们的证明目标是 $\lfloor px_1\rfloor+ q \ge \lfloor p(x_2 + q)\rfloor$ 和 $x_1 - \lfloor px_1\rfloor+ q \ge x_2 + q - \lfloor p(x_2 + q)\rfloor$。
需要注意这个证明目标也有很多题解搞错,lyd 蓝书此处的证明存在上面所说的问题(那条假结论)。
对于第一条:$\lfloor px_1\rfloor+ q = \lfloor px_1 + q\rfloor \ge \lfloor px_2 + pq\rfloor = \lfloor p(x_2 + q)\rfloor$。
对于第二条:$x_1 - \lfloor px_1\rfloor+ q \ge x_2 +q - \lfloor px_2\rfloor \ge x_2 + q - \lfloor p(x_2 +q) \rfloor$。这里第一个不等号用了 $q = 0$ 的证明结论。
不知道你们有没有这个疑问,我补一下。https://www.luogu.com.cn/discuss/551666
其中,$\color{blue}{x -\lfloor px\rfloor}\color{black}{,}\ \color{red}{x-px}$ 图像如此:

处理切割
数据结构
维护三个队列 $Q_1,Q_2,Q_3$:
- $Q_1$ 为未曾切割的蚯蚓;
- $Q_2$ 为切割时形如 $\lfloor px \rfloor$ 的蚯蚓;
- $Q_3$ 为切割时形如 $x- \lfloor px \rfloor$ 的蚯蚓。
操作
模拟题意:每次取最长蚯蚓进行切割。
首先维持 $Q_1$ 单调不增,然后根据前置结论 $2$ ,取最长蚯蚓进行切割所得的两条蚯蚓也比其他蚯蚓切割所得蚯蚓长。
举个例子:
蚯蚓长为 $10,8,7$,$p=0.3$。则切割所得蚯蚓长为 $(3,7),(2,6),(2,5)$,括号表示由同一蚯蚓切割所得。
这样,我们每次在 $Q_1,Q_2,Q_3$ 里查询最大值,切割后加入 $Q_2,Q_3$ 就可以维持 $Q_2,Q_3$ 单调。那么我们只需要取队首比较即可。
输出
第一行
输出也只需要 $i \in [1,m]$ 模拟每一秒,$i \bmod t=0$ 时输出队首即可。
第二行
从大到小查找队首输出并出队即可。
考虑到蚯蚓每一秒都会增长 $q$,我们考虑是否可能 $\mathcal O(1)$ 处理。
不妨令 $i$ 秒时,$q=pl$。
那么我们记录蚯蚓加入队列时的已增加长度 $pl'$,最后用原有长度加上 $pl-pl'$ 即可。
那么我们只需要在加入队列时,加入 $\lfloor px \rfloor-pl'$ 即可。
由于所有蚯蚓都减去了 $pl'$,并不影响 $Q_1,Q_2,Q_3$ 的单调性。
AC代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
const int M=7e6;
int n,m,q,u,v,t;
//Q:手写队列(节约空间)
int Q[4][M+1],front[4],rear[4];
bool cmp(int a,int b){
return a>b;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
scanf("%d %d %d %d %d %d",&n,&m,&q,&u,&v,&t);
for(int i=1;i<=n;i++)scanf("%d",&Q[1][i]);
front[1]=front[2]=front[3]=1;
rear[1]=n;
sort(Q[1]+1,Q[1]+n+1,cmp);//单调不增
int pl=0;
//第一行
for(int i=1;i<=m;i++){
//查找队首最大值
int o,Max=-2147483648;
for(int j=1;j<=3;j++){
if(front[j]<=rear[j]&&Q[j][front[j]]>Max){
Max=Q[j][front[j]];
o=j;
}
}front[o]++;//出队
Max+=pl;pl+=q;
int x=1ll*Max*u/v;
//切割并入队
Q[2][++rear[2]]=x-pl;
Q[3][++rear[3]]=Max-x-pl;
if(i%t==0)printf("%d ",Max);//输出
}putchar(10);//换行
//第二行
for(int i=1;i<=m+n;i++){
//从大到小查找、输出即可。
//同理
int o,Max=-2147483648;
for(int j=1;j<=3;j++){
if(front[j]<=rear[j]&&Q[j][front[j]]>Max){
Max=Q[j][front[j]];
o=j;
}
}front[o]++;
if(i%t==0)printf("%d ",Max+pl);
}
/*fclose(stdin);
fclose(stdout);*/
return 0;
}
题解:[NOIP2016 提高组] 蚯蚓的更多相关文章
- Noip2016 提高组 蚯蚓
刚看到这道题:这题直接用堆+模拟不就可以了(并没有认真算时间复杂度) 于是用priority_queue水到了85分-- (STL大法好) 天真的我还以为是常数问题,于是疯狂卡常--(我是ZZ) 直到 ...
- [NOIp2016提高组]蚯蚓
题目大意: 给你n个不同长度蚯蚓,每秒从里面取出最长的砍下u/v变成两只,又把剩下的加长q. 问你在m之前的t,2t,3t...的时间上,砍的蚯蚓长度, 以及m秒后剩下所有的蚯蚓长度. 思路: 很容易 ...
- Luogu P2827 [NOIp2016提高组]蚯蚓 | 神奇的队列
题目链接 80分思路: 弄一个优先队列,不停地模拟,切蚯蚓时就将最长的那一条出队,然后一分为二入队,简单模拟即可.还要弄一个标记,表示从开始到当前时间每一条蚯蚓应该加上的长度,操作时就加上,入队时就减 ...
- 洛谷P2827 [NOIP2016 提高组] 蚯蚓 (二叉堆/队列)
容易想到的是用二叉堆来解决,切断一条蚯蚓,其他的都要加上一个值,不妨用一个表示偏移量的delta. 1.取出最大的x,x+=delta: 2.算出切断后的两个新长度,都减去delta和q: 3.del ...
- 【题解】NOIP2016提高组 复赛
[题解]NOIP2016提高组 复赛 传送门: 玩具谜题 \(\text{[P1563]}\) 天天爱跑步 \(\text{[P1600]}\) 换教室 \(\text{[P1850]}\) 组合数问 ...
- 【题解】NOIP2016 提高组 简要题解
[题解]NOIP2016 提高组 简要题解 玩具迷题(送分) 用异或实现 //@winlere #include<iostream> #include<cstdio> #inc ...
- NOIP2016提高组解题报告
NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合
- [题解]noip2016普及组题解和心得
[前言] 感觉稍微有些滑稽吧,毕竟每次练的题都是提高组难度的,结果最后的主要任务是普及组抱一个一等奖回来.至于我的分数嘛..还是在你看完题解后写在[后记]里面.废话不多说,开始题解. 第一题可以说的内 ...
- [日记&做题记录]-Noip2016提高组复赛 倒数十天
写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...
- 【NOIP2016提高组day2】蚯蚓
那么我们开三个不上升队列, 第一个记录原来的蚯蚓, 第二个记录乘以p的蚯蚓 第三个记录乘以(1-p)的蚯蚓, 在记录每条就要入队列的时间,就可以求出增加的长度 每次比较三个队列的队首,取最大的值x的切 ...
随机推荐
- Qt 官网开源最新版下载安装保姆级教程【2024-8-4 更新】
➤ 什么是Qt(了解请跳过) ➥ Qt 基本介绍 时至今日,Qt 已经经历了诸多变化.并且在未来,它也会不断地更新迭代.所以如果你想要更准确地了解 Qt,应该通过以下几种方法: ① 官方介绍 根据官方 ...
- Docker自定义镜像输出日志
概述 本文主要解决Docker自定义镜像之后,通过docker logs命令查看不到相关日志的问题 在 Docker 中自定义镜像输出日志,通常需要确保你的应用程序将日志输出到 标准输出(stdout ...
- 基于Kubernetes可扩展的Selenium 并行自动化测试部署及搭建(2)——Win10环境下Kubernetes(k8s)部署
继续上一篇,本篇进行K8S环境部署. K8s部署: 1. 访问k8s-for-docker-desktop 的github地址: https://github.com/AliyunContainer ...
- 信息资源管理综合题之“如何利用PKI实现身份认证和抗抵赖和防篡改等安全措施 ”
一.A企业在网上招标采购某种原材料,B是某个参与招标供应商 1.请讨论如何利用PKI(公钥基础设施),实现A企业接收B报价过程的身份认证.抗抵赖和防篡改等安全措施 二.答案 1.请讨论如何利用PKI( ...
- Python 的 type 及常用魔法方法(上)
魔法方法是 Python 内置方法, 不需要我们手动调用, 它存在的目的是给 解释器 调用的. 比如我们在写 "1 + 1 " 的时候, 这个 "+ " 就会自 ...
- 抽象类&&接口做形参(其实同理)
抽象类:传入该抽象类的子类对象 eg: package javaBasic; public class TestAbstract { public static void main(String[] ...
- SQL注入常用爆库语句
SQL注入的时候,找到了注入点,但是老是搞不清怎么爆库,最后还是得看大佬的WP 最后,终于下定决心自己整理一下爆库的常用语句和思路,如果哪里写的不对麻烦在评论区指出:-D 省流概要 select gr ...
- python时间戳转时间格式
一.两种时间戳转换为时间格式:13位和10位,将时间戳转成时间格式 import time #13位时间戳转时间 tre_timeArray = time.localtime(164601220668 ...
- Manim实现旋转变色特效
在数学动画的世界里,旋转与变色特效无疑是最能吸引观众眼球的元素之一. 今天,就让我们一起探索如何使用Manim框架来实现自定义的旋转变色特效吧! 1. 实现原理 Manim的动画魔法源于Animati ...
- DOS命令快速启动和关闭MySQL服务
为了搭建网格服务框架,在本地创建了MySQL数据库,但是,为了减少内存占用,MySQL数据库服务没有设置为自动启动,所以,需要手动的开启和关闭服务.因此,需要掌握一些短小精悍的DOS命令,下面介绍启动 ...