CSP-S 2020 T4 贪吃蛇 (双队列模拟)
题面
题解
先看数据,T<=10,用平衡树或优先队列是可以拿70分的,大体思路和正解思路是一样的,每次直接修改,然后模拟。
我们模拟的时候,主要是在过程中算出最终被吃的有选择权的蛇的最后选择时刻和被吃时刻,然后按照最后选择时刻从大到小排序,以此判断若ans时刻该蛇已被吃,就把ans提前,
…… 模拟一次复杂度O(nlogn)
(这个博弈思路不用我推了吧?)
那怎么把模拟优化成O(n)的呢?
首先,这个蛇吃蛇的过程有特点,新变弱的蛇要放进序列中,最麻烦的是要在中间找个位置插进去……要是直接加在后面该多好!
那么我们首先考虑直接加后面的情况吧:
拿出序列中最大的一个,记为 x,最小的一个,记为 y,y 前面次小的一个,咱叫它 z
这时,发生了一件大事:我们发现 x-y <= z !!!
把它直接放后面,于是轮到次大的 s 跟 x-y 比,
由于 s <= x → s - x <= 0,所以 s - (x-y) = y + (s - x) <= y ,
又因为 y <= z ,堆出 s - (x-y) <= y <= z ,它又可以放到 z 后面!!!
把 s 换为 x' , (x-y) 换为 y',s - (x-y)就为新的 (x' - y') ,然后倒回第一个“”的那一排,于是循环开始了……
!
得出结论:一旦过程中最大的蛇 - 最小的蛇 可以放在最后,那么直到游戏结束,所有的新蛇都可以放在最后
好那么之前,在还不能放最后的时间里,所有的新蛇都得插入序列中了!
……
真烦,先把它放一边吧!
把新蛇单独放到第二个队列里,记原序列为A1~n,此时的最大需要在两个队列开头比较,最小需要在两个队尾比较
在不能放最后的时间里,An 、An-1、An-2 ... 一定依次作为最小的蛇被吃(如果中途有新蛇能放在最后的话,你懂的,如果是B队列最后一个当最小,看下面的推导),
由于选出的最大蛇一次不比一次大(这很显然嘛),最小蛇一次不比一次小(↑),那么减出来的新蛇一定单调不增!!
那么此时可以放心地把后面的新蛇都放到 B 队列尾了!如果B队列尾的蛇被提出来了呢?那说明已经比 A队列尾小了,之前为什么不直接放A队列尾呢?
不要问我为什么两个队列仍符合前面一个队列的结论,因为它们在模拟中本质上是一个队列。
好了,正解思路已经出来了,数组模拟两个单调队列,每次找两个队列头部最大的和尾部最小的这两条蛇,战胜的新蛇能放A队尾就放A队尾,否则放B队尾。
处理出过程以后呢?我们其实可以用桶排,把蛇按最后选择时刻放桶里拍序,博弈处理……
模拟一次复杂度O(n)
总复杂度O(Tn)
CODE
#include<ctime>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1000005
#define LL long long
#define ULL unsigned long long
#define DB double
#define ENDL putchar('\n')
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s == '-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 1000000007;
int n,m,i,j,s,o,k;
int a[MAXN];
struct AS{
int l,r;
}as[MAXN];
bool cmp2(AS a,AS b) {return a.r < b.r;}
struct it{
int nm,id;
it(){nm = id = 0;}
it(int N,int I){nm = N;id = I;}
};
it q1[MAXN];
it q2[MAXN];
int h1,t1,h2,t2;
bool operator >(it a,it b) {return a.nm == b.nm ? (a.id > b.id) : (a.nm > b.nm);}
bool operator <(it a,it b) {return b > a;}
bool CMP(it a,it b) {return a > b;}
int bu[MAXN],cntq;
int solve() {
h1 = 1;t1 = n;
h2 = 1;t2 = 0;
cntq = 0;
// printf("root:%d\n",root);
// ENDL;
for(int i = 1;i <= n;i ++) {
q1[i] = it(a[n-i+1],n-i+1);
as[i].l = as[i].r = -1;
bu[i] = 0;
}
for(int i = n;i > 1;i --) {
it x,y;
if(h2 > t2 || (h1 <= t1 && q1[h1] > q2[h2])) x = q1[h1 ++];
else x = q2[h2 ++];
if(h2 > t2 || (h1 <= t1 && q1[t1] < q2[t2])) y = q1[t1 --];
else y = q2[t2 --];
as[y.id].r = i;
if(as[y.id].l > 0) {
bu[as[y.id].l] = y.id;
}
as[x.id].l = i;
x.nm -= y.nm;
if(x < q1[t1]) q1[++ t1] = x;
else q2[++ t2] = x;
// printf("eaten: (%d)%d ([%d,%d] [%d,%d])\n",y.id,y.nm,h1,t1,h2,t2);
}
int ans = 1;
for(int i = 1;i <= n;i ++) {
if(bu[i]) {
if(ans < as[bu[i]].r) ans = i;
}
}
return ans;
}
int main() {
// freopen("snakes.in","r",stdin);
// freopen("snakes.out","w",stdout);
srand(time(0));
int T = read()-1;
n = read();
for(int i = 1;i <= n;i ++) {
a[i] = read();
}
// sort(q0 + 1,q0 + 1 + n,CMP);
printf("%d\n",solve());
while(T --) {
m = read();
for(int i = 1;i <= m;i ++) {
s = read();o = read();
a[s] = o;
}
printf("%d\n",solve());
}
return 0;
}
CSP-S 2020 T4 贪吃蛇 (双队列模拟)的更多相关文章
- 小项目特供 贪吃蛇游戏(基于C语言)
C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次. 是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第 ...
- JS高级---面向对象的编程思想(贪吃蛇梳理)
面向对象的编程思想(贪吃蛇梳理) 模拟贪吃蛇游戏,做的项目 地图: 宽,高,背景颜色,因为小蛇和食物都是相对于地图显示的, 这里小蛇和食物都是地图的子元素, 随机位置显示, 脱离文档流的, 地图也需要 ...
- 多线程的Python 教程--“贪吃蛇”
本指南的里代码可以在这里下载: threadworms.py ,或者从 GitHub.代码需要 Python 3 或 Python 2 ,同时也需要安装 Pygame . 点击查看大版本图片 ...
- javascript 编写的贪吃蛇
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Linux Curses编程实现贪吃蛇
curses库 简单而言,提供UNIX中多种终端 操作光标和显示字符 的接口.我们常见的vi就是使用curses实现的.现在一般都用ncurses库. Linux下curses函数库 Linux ...
- 贪吃蛇AI
贪吃蛇AI 作者:CodeNoob 转载请标明作者和出处 序言 前几天在网上看到一张让人涨姿势的图片,这张图片我很早以前看过,当时就觉得肯定是程序实现的,只是当时还比较渣,不会算法.这次学了java也 ...
- [C语言]贪吃蛇_结构数组实现
一.设计思路 蛇身本质上就是个结构数组,数组里存储了坐标x.y的值,再通过一个循环把它打印出来,蛇的移动则是不断地刷新重新打印.所以撞墙.咬到自己只是数组x.y值的简单比较. 二.用上的知识点 结构数 ...
- c语言贪吃蛇详解3.让蛇动起来
c语言贪吃蛇详解3.让蛇动起来 前几天的实验室培训课后作业我布置了贪吃蛇,今天有时间就来写一下题解.我将分几步来教大家写一个贪吃蛇小游戏.由于大家c语言未学完,这个教程只涉及数组和函数等知识点. 上次 ...
- python 贪吃蛇
#!/usr/bin/python3 ''' 项目分析: -构成 -蛇Snake -实物Food -世界World -蛇和食物属于整个世界 class world: self.snake self.f ...
随机推荐
- Tensor的组合与分块
>>> a = torch.Tensor([[1,2],[3,4]])>>> atensor([[1., 2.], [3., 4.]]) >>> ...
- canal的使用
一.简介 canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实 ...
- SAP 隐式增强 Enhancement point
1.进入编辑器:SE38/SE37/SE24 Edit-->Enhancement Operations-->Create Option 2.填写相关信息,点击对号. 3.点击Enhanc ...
- Python收集这些视频只是单纯的想做做壁纸,大家不要误会
首先澄清一下,我用Python收集这些视频,绝不是想做别的什么,真的只是用来做动态壁纸,大家不要误会!我不是那样的人~ 这样的不过份吧 (这个动图看不看的到就看有没有缘分了 ) 阅读本文你需要准备 1 ...
- Unsupported major.minor version 52.0 (unable to load class org.apache.kafka.clients.producer.Produce异常解决方法
在控制台输入java -version,查看自己的版本是多少,我的查出来是1.8的.随后将服务器上的改为1.8的就可以了.
- Tapdata Cloud 2.1.5来啦:新增支持Amazon RDS数据库,错误日志查询更便捷,Agent部署细节再优化
需求持续更新,优化一刻不停--Tapdata Cloud 2.1.5 来啦! 最新发布的版本中,数据连接再上新,同时新增任务报错相关信息快速查询入口,开始支持 JVM 参数自定义设置. 更 ...
- day11 - 多线程
1内容 进程.线程介绍 Java中 线程的实现方式 Thread 类 Runnable 接口 Callable 接口 线程相关的方法 线程安全问题 - 同步技术 线程等待唤醒机制 进程(Process ...
- 练习-用if语句替换三元运算符和选择结构-标准的switch语句
if语句和三元运算符的互换 在某些简单的应用中,if语句是可以和三元运算符互换使用的 public static void main(String[] args) { int a = 10; int ...
- windows10 使用elasticsearch和kibana
https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.6.2-windows-x86_64.zip https:// ...
- 0基础就可以上手的Spark脚本开发-for Java
前言 最近由于工作需要,要分析大几百G的Nginx日志数据.之前也有过类似的需求,但那个时候数据量不多.一次只有几百兆,或者几个G.因为数据都在Hive里面,当时的做法是:把数据从Hive导到MySQ ...