码迷,mamicode.com
首页 > 其他好文 > 详细

【比赛】【SMOJ 2019.4.21】

时间:2019-08-01 11:47:20      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:mes   http   segment   一个   应该   意义   最小   code   分层图   

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

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


\(\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}\)

【比赛】【SMOJ 2019.4.21】

标签:mes   http   segment   一个   应该   意义   最小   code   分层图   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!