2016-C24-team2

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

||Run ID||Time||Size||Problem||Language||Result||
||378||4:59:16||2691||J||g++0x||OK||
||377||4:56:47||2685||J||g++0x||Wrong answer||
||358||2:17:07||1498||F||g++0x||OK||
||348||1:18:21||1602||A||g++0x||OK||
||343||0:22:48||356||D||gcc||OK||
||342||0:17:47||268||D||gcc||Wrong answer||

== 流水账 ==
=== TsReaper ===
开始的时候starve学长有课,我和hzf学长先开始。hzf学长很快发现D的做法,我写的时候又忘记了一个特例WA了一次,'''D2y22'''。学长接下来又想到了A的做法,我们用二位偏序改进了一下'''A1y78'''。我写A的时候hzf学长又想到了F的做法,因为我没怎么写过维护凸壳+dp所以敲了一个暴力对拍~~结果暴力写错了浪费了一点时间~~,'''F1y137'''。

然后starve学长来了,似乎想到了E的做法。hzf学长提出了一个反例~~然而这个反例并不符合题目限制,但是我们三个人都没有发现...~~,之后我们分别纠结了一段时间H和E。最后90分钟我看了一下J,想到了并查集的写法。但是因为程序比较难写,时间也比较紧,出现了并查集写错,函数忘记return等错误,好在最后答对了,'''J2y299'''。

== 总结 ==
=== TsReaper ===
 * 做得好的地方
   * A和F的想法都很不错...
 * 做得不好的地方
   * E题的反例举错了,我们还没有发现...
   * J题出现了很多低级失误,最后时刻也要淡定啊...

== 题解 ==
D题比较简单,略过...

=== A - MEX-Query ===
把询问按右端点从小到大排序,用树状数组维护每种数在当前右端点的左边最后出现的位置。这样只需要求“最后出现的位置在左端点左边的数,最小是多少”,用树状数组维护前缀最小值即可。

我们也可以把这个问题转化为二位偏序。如果序列中有n个x,那么它们会把序列分成n+1个区间。如果有一个询问区间恰好完全被其中某个区间包含,则这个询问的答案至多是x。

也就是说,设这n+1个区间中的某个区间为[L,R],询问区间为[l,r]。只要L<=l且-R<=-r,则该询问的答案至多是x。这就是一个二位偏序问题,只不过树状数组维护的是前缀最小值,而不是前缀和。

=== F - Just Another Sequence Problem ===
设f[i,j]表示以[i,j]区间为最后一个区间的答案,sum[]表示前缀和,显然有f[i,j] = max(f[k,i-1] + (sum[i-1]-sum[k-1]) * (sum[j]-sum[i-1])),展开来就是f[i,j] = max(f[k,i-1] - sum[k-1]*(sum[j]-sum[i-1]) + sum[i-1]*(sum[j]-sum[i-1]))。这里面只有f[k,i-1] - sum[k-1]*(sum[j]-sum[i-1])这一部分与k有关。

我们可以把这个部分看成直线,f[k,i-1]是截距,-sum[k-1]是斜率。那么问题就变成了:有i-1条直线(一次函数),还有j-i+1个不同的x值,求对于每个x值的最大函数值。我们只需要维护一个下凸壳,再对于每个x二分一下即可。复杂度O(n^2^logn)

=== J - Dividing Area ===
我们把询问倒过来做,从连线变成擦线。一开始形成同一个三角形的三条有向线段属于一个集合,该集合的答案就是三角形面积的两倍。没有构成三角形的有向线段属于-1集合,答案是-1。接下来每擦掉一条线,两个集合就会合并,合并后集合的答案就是两个集合答案相加(当然如果合并前有一个集合是-1,那么合并后两个集合里的元素都属于-1)。~~是一道说着容易写起来麻烦的题目~~。

== 补题 ==
Run IDTimeSizeProblemLanguageResult
3784:59:162691Jg++0xOK
3774:56:472685Jg++0xWrong answer
3582:17:071498Fg++0xOK
3481:18:211602Ag++0xOK
3430:22:48356DgccOK
3420:17:47268DgccWrong answer

流水账

TsReaper

开始的时候starve学长有课,我和hzf学长先开始。hzf学长很快发现D的做法,我写的时候又忘记了一个特例WA了一次,D2y22。学长接下来又想到了A的做法,我们用二位偏序改进了一下A1y78。我写A的时候hzf学长又想到了F的做法,因为我没怎么写过维护凸壳+dp所以敲了一个暴力对拍结果暴力写错了浪费了一点时间F1y137

然后starve学长来了,似乎想到了E的做法。hzf学长提出了一个反例然而这个反例并不符合题目限制,但是我们三个人都没有发现...,之后我们分别纠结了一段时间H和E。最后90分钟我看了一下J,想到了并查集的写法。但是因为程序比较难写,时间也比较紧,出现了并查集写错,函数忘记return等错误,好在最后答对了,J2y299

总结

TsReaper

  • 做得好的地方
    • A和F的想法都很不错...
  • 做得不好的地方
    • E题的反例举错了,我们还没有发现...
    • J题出现了很多低级失误,最后时刻也要淡定啊...

题解

D题比较简单,略过...

A - MEX-Query

把询问按右端点从小到大排序,用树状数组维护每种数在当前右端点的左边最后出现的位置。这样只需要求“最后出现的位置在左端点左边的数,最小是多少”,用树状数组维护前缀最小值即可。

我们也可以把这个问题转化为二位偏序。如果序列中有n个x,那么它们会把序列分成n+1个区间。如果有一个询问区间恰好完全被其中某个区间包含,则这个询问的答案至多是x。

也就是说,设这n+1个区间中的某个区间为[L,R],询问区间为[l,r]。只要L<=l且-R<=-r,则该询问的答案至多是x。这就是一个二位偏序问题,只不过树状数组维护的是前缀最小值,而不是前缀和。

F - Just Another Sequence Problem

设f[i,j]表示以[i,j]区间为最后一个区间的答案,sum[]表示前缀和,显然有f[i,j] = max(f[k,i-1] + (sum[i-1]-sum[k-1]) * (sum[j]-sum[i-1])),展开来就是f[i,j] = max(f[k,i-1] - sum[k-1]*(sum[j]-sum[i-1]) + sum[i-1]*(sum[j]-sum[i-1]))。这里面只有f[k,i-1] - sum[k-1]*(sum[j]-sum[i-1])这一部分与k有关。

我们可以把这个部分看成直线,f[k,i-1]是截距,-sum[k-1]是斜率。那么问题就变成了:有i-1条直线(一次函数),还有j-i+1个不同的x值,求对于每个x值的最大函数值。我们只需要维护一个下凸壳,再对于每个x二分一下即可。复杂度O(n2logn)

J - Dividing Area

我们把询问倒过来做,从连线变成擦线。一开始形成同一个三角形的三条有向线段属于一个集合,该集合的答案就是三角形面积的两倍。没有构成三角形的有向线段属于-1集合,答案是-1。接下来每擦掉一条线,两个集合就会合并,合并后集合的答案就是两个集合答案相加(当然如果合并前有一个集合是-1,那么合并后两个集合里的元素都属于-1)。是一道说着容易写起来麻烦的题目

补题

附加文件