比赛SMOJ 2019.4.21
Posted info---tion
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了比赛SMOJ 2019.4.21相关的知识,希望对你有一定的参考价值。
第三次体会到考试出超纲题的绝望……
不要问我前两次在什么时候
\(\mathrmT1\)
\(\colorredTotally\ Brute\ Force!\)
就是个暴力……
我们一开始假设整个数组是一个区间\([1,n]\)的区间,然后每次操作都会把区间从中间断开。(可以理解成:把中间的数删去后,左右两侧的数会分成两个区间)
这里要说一下这些区间的定义:
struct Segmentint st,len;;
\(st\)表示这个区间中最小的数;\(len\)表示这个区间的长度。
比如说,原题的样例\(1\),进行了第一次删除操作后,整个数组就被分成了两个区间:分别是\(1\sim2,5\sim8\)。用结构体表示就是
(Segment)1,2;
(Segment)5,4;
然后,假如我们要处理一个删除操作,这个删除操作会影响到连续的若干个区间的话,有两个操作是所有情况通用的:
- 修改最左区间的\(len\)
新建一个区间。
这个区间的\(st\)是数组中的第\(ri\)个数(\(ri\)就是删除操作的\(ri\)),但这个第\(ri\)个数的准确数值要从
Segment
那个结构体中得到(因为\(st\)存的是准确数值)。这个区间的\(len\)就是受到影响的最右边的区间的\(len-\text最右边的区间被删去部分的长度\)
也许你会问:为什么不直接修改最右边的区间呢?
假如删除操作只影响了一个区间,那么这个区间就会分裂成两个区间,所以还是要新建一个区间的。
做完上述两个操作之后,就把受到影响的,且既不是最左也不是最右的区间删掉。
删完之后,再看一下:如果最左区间或者最右区间的\(len=0\),就把这个区间也删掉。
插入删除操作就跟在顺序线性表中插入元素一样,时间复杂度是\(\mathrmO(n)\)的。
重点其实应该是修改最左区间和插入最右区间这两个操作。
看代码吧:\(\mathrmCode\)
\(\mathrmT2\)
这就是超纲题了。
建议大家先看看这一题和这一题并尝试将代码写出来再继续往下看。
回到这一题。
很明显,\(\mathrmT\)很大,而每条边的权值又很小,这时,同余系下最短路就能发挥用场了。
在跳楼机那一题中,我们用\(dis[i]\)表示路径长度在模一个指定边权之后的数值为\(i\)的最小值。(其实和分层图有点像)
在这里,我们只需要把\(dis[i]\)扩多一维变成\(dis[i][j]\),\(i\)表示在第\(i\)个节点,\(j\)的意义和上面的\(i\)一样。
然后我们就可以像跳楼机一样猥琐操作了:
- 首先,找到 与起点或终点直接相连的边的最小边权\(len\) 作为模数(这样做是为了加快后面的\(\mathrmSPFA\))。
然后就像分层图上最短路一样直接跑\(\mathrmSPFA\)。
具体来讲就是
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; //从代码里抄的
跑完\(\mathrmSPFA\)后,我们要取的是\(dis[n-1][\mathrmT\%(len \times 2)]\)的值,这样的话,\(dis\)中最短路的长度加上若干个\(len\)之后就会等于\(\mathrmT\)了。
问题来了:为什么是\(\%(len \times 2)\)而不是\(\%len\)呢?
因为我们到了终点或者还停留在起点时,只有在同一条边上走偶数次才能回到原处。
接着,我们可以把\(\mathrmT\)变形成一次函数的形式(就是\(ax+b\ (a=e.len,b<a)\))。
我们在同一条边上走偶数次,就等同于将\(\mathrmT=ax+b\)这个式子的\(a\)减去了一个偶数。
设被减去后的\(\mathrmT=a'x+b\),则很明显:
\(a' \equiv a \pmod 2\)
(就是说\(a'\)和\(a\)奇偶性相同)换言之,我们要使\(dis\)数组中的最短路长度的\(a\)和\(\mathrmT\)的\(a\)同奇同偶。
然后,下面的结论就
很容易证明了:设\(\mathrmT=a_1x+b,\mathrmT\%(len\times 2)=a_2x+b\),则\(a_1 \equiv a_2 \pmod2\)。
所以我们要做的就是:
- 找到与起点或终点直接相连的边的最小边权\(len\);
- 以\(len\)作为模数跑剩余系最短路
- 判断\(dis[n-1][\mathrmT\%(len \times 2)]\)是否\(\leqslant \mathrmT\)。
大概就是这样了,剩下的细节就看看代码吧
(对自己代码的思维清晰程度总是有着谜一般的信心)
\(\mathrmT3\)
其实这一题是码量最短的。
一眼看过去以为是博弈论,但随后发现其实就是一个贪心:
以\(\mathrmT\)节点为根,我们就可以一层一层地推(假设\(\mathrmT\)节点的深度为\(0\))
- 第\(1\)层最多只能放\(1\)个棋子;
- 第\(2\)层最多只能放\(3\)个棋子;
- 第\(3\)层最多只能放\(7\)个棋子;
- 。。。
- 第\(n\)层就最多能放\(2n-1\)个棋子。
但是:如果一个节点有多于一个儿子的话,那我们就不能每个节点都来一个\(2n+1\)了。
正确的转移方法是:找到所有儿子所在的子树中,深度最深的子树,把\(2n+1\)个棋子转移到这个最深的儿子。其他的儿子就直接只给\(1\)个棋子,然后再重新转移。
正确性容易证明。
以上是关于比赛SMOJ 2019.4.21的主要内容,如果未能解决你的问题,请参考以下文章
解题报告 smoj 2019初二创新班(2019.3.17)
假定要建立一个关于篮球职业联盟的数据库,需管理如下信息: 每个球队有球队名称所在城市; 每位球员有球员姓名薪酬; 每场比赛有比赛编号比赛时间比赛结果参加比赛的主场球队参加比赛的客场球