题面

题解

先看数据,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 贪吃蛇 (双队列模拟)的更多相关文章

  1. 小项目特供 贪吃蛇游戏(基于C语言)

    C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次. 是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第 ...

  2. JS高级---面向对象的编程思想(贪吃蛇梳理)

    面向对象的编程思想(贪吃蛇梳理) 模拟贪吃蛇游戏,做的项目 地图: 宽,高,背景颜色,因为小蛇和食物都是相对于地图显示的, 这里小蛇和食物都是地图的子元素, 随机位置显示, 脱离文档流的, 地图也需要 ...

  3. 多线程的Python 教程--“贪吃蛇”

    本指南的里代码可以在这里下载:  threadworms.py ,或者从  GitHub.代码需要  Python 3 或 Python 2 ,同时也需要安装  Pygame . 点击查看大版本图片 ...

  4. javascript 编写的贪吃蛇

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

  5. Linux Curses编程实现贪吃蛇

    curses库 简单而言,提供UNIX中多种终端 操作光标和显示字符 的接口.我们常见的vi就是使用curses实现的.现在一般都用ncurses库. Linux下curses函数库    Linux ...

  6. 贪吃蛇AI

    贪吃蛇AI 作者:CodeNoob 转载请标明作者和出处 序言 前几天在网上看到一张让人涨姿势的图片,这张图片我很早以前看过,当时就觉得肯定是程序实现的,只是当时还比较渣,不会算法.这次学了java也 ...

  7. [C语言]贪吃蛇_结构数组实现

    一.设计思路 蛇身本质上就是个结构数组,数组里存储了坐标x.y的值,再通过一个循环把它打印出来,蛇的移动则是不断地刷新重新打印.所以撞墙.咬到自己只是数组x.y值的简单比较. 二.用上的知识点 结构数 ...

  8. c语言贪吃蛇详解3.让蛇动起来

    c语言贪吃蛇详解3.让蛇动起来 前几天的实验室培训课后作业我布置了贪吃蛇,今天有时间就来写一下题解.我将分几步来教大家写一个贪吃蛇小游戏.由于大家c语言未学完,这个教程只涉及数组和函数等知识点. 上次 ...

  9. python 贪吃蛇

    #!/usr/bin/python3 ''' 项目分析: -构成 -蛇Snake -实物Food -世界World -蛇和食物属于整个世界 class world: self.snake self.f ...

随机推荐

  1. 不同的子序列问题I

    不同的子序列问题I 作者:Grey 原文地址: 不同的子序列问题I 题目链接 LeetCode 115. 不同的子序列 暴力解法 定义递归函数 int process(char[] str, char ...

  2. Redis基础与性能调优

    Redis是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库.缓存服务或消息服务使用. Redis支持多种数据结构,包括字符串.哈希表.链表.集合.有序集合.位图.Hyperloglogs等. ...

  3. UiPath官网认证中文教程

    RPA之家公众号:RPA之家 RPA之家官网:http://rpazj.com 斗鱼直播:http://www.douyu.com/rpazj UiPath中文社区QQ群:465630324 RPA& ...

  4. 使用dnSpy对无源码EXE或DLL进行反编译并且修改

    背景 总有一些特殊情况,我们没有源码,但是某个C#程序集dll或者可执行程序exe影响到我们代码的正常运行,我们希望得到源码,能改掉或者修改某些bug,但是苦于没有源码,这个时候可以用dnspy进行源 ...

  5. 【Nim 游戏】 学习笔记

    前言 没脑子选手随便一道博弈论都不会 -- 正文 Nim 游戏引入 这里给出最简单的 \(Nim\) 游戏的题目描述: \(Nim\) 游戏 有两个顶尖聪明的人在玩游戏,游戏规则是这样的: 有\(n\ ...

  6. 如何等待ajax完成再执行相应操作

    ajax广泛应用于异步请求,对于大多数业务来说,这是十分方便的,但对于一些特殊的业务,ajax的异步性会起到相反的作用. 例如在ajax请求成功后,后续的操作需要依赖ajax执行成功后的相应操作. / ...

  7. Throwable类中3个异常处理的方法和finally代码块

    /* Throwable类中定义了3个异常处理的方法 String getMessage() 返回此 throwable 的简短描述. String toString() 返回此 throwable ...

  8. List集合_介绍&常用方法和ArrayList集合

    List集合 我们掌握了Collection接口的使用后,再来看看Collection接口中的子类,他们都具备那些特性呢? 接下来,我们一起学习Collection中的常用几个子类(java.util ...

  9. vue2升级vue3指南(一)—— 环境准备和构建篇

    1.nodejs和npm 注意二者的版本,版本过低需要升级,本人升级后的版本如下: $ node -v v16.15.1 $ npm -v 8.11.0 2.package.json 和依赖升级 由于 ...

  10. linux Error downloading packages free 0 * needed 71 k

    linux  Error downloading packages free   0      * needed 71 k 原因:硬盘空间不足 查看磁盘大小 /]# df -hl 从/主目录开始搜索, ...