【比赛】【SMOJ 2019.4.21】

第三次体会到考试出超纲题的绝望……

不要问我前两次在什么时候


\(\mathrm{T1}\)

\(\color{red}{Totally\ Brute\ Force!}\)

就是个暴力……

我们一开始假设整个数组是一个区间\([1,n]\)的区间,然后每次操作都会把区间从中间断开。(可以理解成:把中间的数删去后,左右两侧的数会分成两个区间

这里要说一下这些区间的定义:

struct Segment{int st,len;};

\(st\)表示这个区间中最小的数;\(len\)表示这个区间的长度

比如说,原题的样例\(1\),进行了第一次删除操作后,整个数组就被分成了两个区间:分别是\(1\sim2,5\sim8\)。用结构体表示就是

(Segment){1,2};
(Segment){5,4};

然后,假如我们要处理一个删除操作,这个删除操作会影响到连续的若干个区间的话,有两个操作是所有情况通用的:

  1. 修改最左区间的\(len\)
  2. 新建一个区间。

    这个区间的\(st\)是数组中的第\(ri\)个数(\(ri\)就是删除操作的\(ri\)),但这个第\(ri\)个数的准确数值要从Segment那个结构体中得到(因为\(st\)存的是准确数值)。

    这个区间的\(len\)就是受到影响的最右边的区间的\(len-\text{最右边的区间被删去部分的长度}\)

也许你会问:为什么不直接修改最右边的区间呢?

假如删除操作只影响了一个区间,那么这个区间就会分裂成两个区间,所以还是要新建一个区间的。

做完上述两个操作之后,就把受到影响的,且既不是最左也不是最右的区间删掉

删完之后,再看一下:如果最左区间或者最右区间的\(len=0\),就把这个区间也删掉。

插入删除操作就跟在顺序线性表中插入元素一样,时间复杂度是\(\mathrm{O}(n)\)的。

重点其实应该是修改最左区间插入最右区间这两个操作。

看代码吧:\(\mathrm{Code}\)


\(\mathrm{T2}\)

这就是超纲题了。

建议大家先看看这一题这一题并尝试将代码写出来再继续往下看。

回到这一题。

很明显,\(\mathrm{T}\)很大,而每条边的权值又很小,这时,同余系下最短路就能发挥用场了。

在跳楼机那一题中,我们用\(dis[i]\)表示路径长度在模一个指定边权之后的数值为\(i\)的最小值。(其实和分层图有点像)

在这里,我们只需要把\(dis[i]\)扩多一维变成\(dis[i][j]\),\(i\)表示在第\(i\)个节点,\(j\)的意义和上面的\(i\)一样。

然后我们就可以像跳楼机一样猥琐操作了:

  • 首先,找到 与起点或终点直接相连的边的最小边权\(len\) 作为模数(这样做是为了加快后面的\(\mathrm{SPFA}\))。
  • 然后就像分层图上最短路一样直接跑\(\mathrm{SPFA}\)。

    具体来讲就是

    if( dis[h.pos][h.mval]+e.len<dis[e.to][(h.mval+e.len)%mod] )
        dis[e.to][(h.mval+e.len)%mod]=dis[h.pos][h.mval]+e.len; //从代码里抄的
  • 跑完\(\mathrm{SPFA}\)后,我们要取的是\(dis[n-1][\mathrm{T}\%(len \times 2)]\)的值,这样的话,\(dis\)中最短路的长度加上若干个\(len\)之后就会等于\(\mathrm{T}\)了。

    问题来了:为什么是\(\%(len \times 2)\)而不是\(\%len\)呢?

  • 因为我们到了终点或者还停留在起点时,只有在同一条边上走偶数次才能回到原处。

    接着,我们可以把\(\mathrm{T}\)变形成一次函数的形式(就是\(ax+b\ (a=e.len,b<a)\))。

    我们在同一条边上走偶数次,就等同于将\(\mathrm{T}=ax+b\)这个式子的\(a\)减去了一个偶数

    设被减去后的\(\mathrm{T}=a'x+b\),则很明显:

    \(a' \equiv a \pmod 2\)(就是说\(a'\)和\(a\)奇偶性相同)

    换言之,我们要使\(dis\)数组中的最短路长度的\(a\)和\(\mathrm{T}\)的\(a\)同奇同偶

    然后,下面的结论就很容易证明了:

    设\(\mathrm{T}=a_1x+b,\mathrm{T}\%(len\times 2)=a_2x+b\),则\(a_1 \equiv a_2 \pmod{2}\)。

所以我们要做的就是:

  1. 找到与起点或终点直接相连的边的最小边权\(len\);
  2. 以\(len\)作为模数跑剩余系最短路
  3. 判断\(dis[n-1][\mathrm{T}\%(len \times 2)]\)是否\(\leqslant \mathrm{T}\)。

大概就是这样了,剩下的细节就看看代码吧

(对自己代码的思维清晰程度总是有着谜一般的信心)

\(\mathrm{Code}\)


\(\mathrm{T3}\)

其实这一题是码量最短的。

一眼看过去以为是博弈论,但随后发现其实就是一个贪心:

以\(\mathrm{T}\)节点为根,我们就可以一层一层地推(假设\(\mathrm{T}\)节点的深度为\(0\))

  • 第\(1\)层最多只能放\(1\)个棋子;
  • 第\(2\)层最多只能放\(3\)个棋子;
  • 第\(3\)层最多只能放\(7\)个棋子;
  • 。。。
  • 第\(n\)层就最多能放\(2n-1\)个棋子。

但是:如果一个节点有多于一个儿子的话,那我们就不能每个节点都来一个\(2n+1\)了。

正确的转移方法是:找到所有儿子所在的子树中,深度最深的子树,把\(2n+1\)个棋子转移到这个最深的儿子。其他的儿子就直接只给\(1\)个棋子,然后再重新转移。

正确性容易证明。

\(\mathrm{Code}\)

原文地址:https://www.cnblogs.com/info---tion/p/11281428.html

时间: 2024-08-30 14:56:36

【比赛】【SMOJ 2019.4.21】的相关文章

解题报告 smoj 2019初二创新班(2019.3.17)

目录 解题报告 smoj 2019初二创新班(2019.3.17) T1:找玩具 题目描述 题意转化 分析 代码 优化(代码复杂度) T2:闯关游戏 题目描述 分析 代码 T3:子数组有主元素 题目描述 分析 代码(\(O(nm\log n)\)) 优化 代码(\(O(nm)\)) 解题报告 smoj 2019初二创新班(2019.3.17) 时间:2019.3.21 T1:找玩具 题目描述 在游戏开始之前,游戏大师在房间的某些地方隐藏了N个玩具.玩具编号为1到N.您的任务是尽可能多地找到这些玩

解题报告 smoj 2019初二创新班(2019.3.31)

目录 T1:单人游戏 题目描述 分析 证明:游戏必定存在环 证明:以最短路径到达环必定最优 证明:移动时不可能越过环的结尾 DP实现 代码 T2:赚金币 题目描述 分析 代码 T3:抽奖 题目描述 分析 代码 时间:2019.4.5 比赛网址 T1:单人游戏 题目描述 棋盘由N个格子排成一行,从左到右编号为1到N,每个格子都有一个相关的价值. 最初,棋子位于第1个格子上,当前方向是向右的. 在每个回合中,棋子在当前方向上行走零步或多步,每一步就是走一个格子.然后在下一回合中,棋子的方向反转. 一

2019 1 21 赵松儒

1 //strlen - calculate the length of a string// 2 3 #include <stdio.h> 4 5 int strlens(const char *s); 6 char strcats(char *dest, const char *src); 7 8 #define NUM 100 9 10 int main(void) 11 { 12 char c[NUM]; 13 char *s; 14 s = c; 15 16 printf("

2019.2.21 T2题解

meet 大概思路就是 , 找出相交的路径 , 判断方向 , 分类讨论.. 假设已经找出了相交路径 ... 若方向相同 , 则找到相交路径上边权的最大值 , 若最大值>出发时间差 , 则可行. 原因: 由于方向相同所以在相交路径上这两个点的相对距离是不变的,看最大的边权即可. 这个东西用st表就可以搞定 若方向不同,就看看他们相遇的位置是不是相交路径上各个(不一定是最两头的点)边的端点之一. 因为题中说在边上才算 , 点不能算到边上. 所以不在点上就一定会在边上相遇. 然后就是怎么找相交路径了.

2019.1.21 单词接龙

题目传送门 主要就是简单的字符串+深搜 每次枚举可以接下去的单词 再枚举最后取i位作为后缀 枚举不到单词就取长度 上代码 #include<iostream> #include<cstring> #include<cstdio> using namespace std; int n,len,book[25]; string word[25],fir,ne; bool judge(string str,string left)//判断是否可以接下去 { int l=str

2019.1.21每日一题

Description 求 1-n 1\sim n 1-n 之间素数个数. 输入格式 一行一个数 n n n . 输出格式 一行一个数,表示答案. 样例 样例输入 10 样例输出 4 样例解释 1 2,3,5,72,3,5,72,3,5,7 #include<stdio.h>int sum(int n);int main(){    int i,a;    int result=0;    scanf("%d",&a);    for(i=2;i<=a;i++

2019.1.21

jQuery 1     ready()函数规定当ready事件发生时执行的代码(仅能用于当前文档):        语法:(1)$ (document).ready(function(){});                   (2)$().ready(function(){});   (3)   $(function(){}); 2     语法:$(selector).action(); 3     方法:  (1)hide()   隐藏文本: (2)show()显示文本: (3)fa

2019 1 21 付铖

/*strlen strcpy strcmp strcat 查看功能是什么,并自定义函数,与之功能一至*/ #include<stdio.h> int strlen_long(char * ch); void strcpy_cpy(char * c,char * ch); int strcmp_compare(char * ch ,char * c); int strcat_link(char * sz,char * ch,const char * c); int main(void) { i

2019.03.21 admin

1.新建文件创建一个应用类 stu Python manage.py startapp stu 2,创建应用类 记得在setting中的installed_apps中添加应用 student/models.py中创建Stu模型类   写下自己需要的字段名   # -*- coding: utf-8 -*-   from __future__ import unicode_literals       from django.db import models       # Create your