POI2011练习记录

Posted by sjj118 on 2016-11-21

Conspiracy

可以发现这是一个2-sat模型,单2-sat只能求合法方案,不能求方案数。发现一个方案每个部分的人都最多有一个到另一个部分去,所以就可以枚举哪些人换位置判断是否合法了。

Lollipop

一个比较暴力的想法就是每个询问都利用单调性直接找区间,这样是\(O(nm)\)的。另a为原数组,s为其前缀和,我们发现在q<=s[n]时,如果固定左端点l为1,那么一定能找到一个右端点使得s[r]=q或q-1,如果s[r]=q则找到了答案,否则s[r]=q-1。接下来我们讨论a[l]与a[r+1]: 如果a[l]=1,a[r+1]=1,那么区间[l,r+1]等于q; 如果a[l]=1,a[r+1]=2,那么区间[l+1,r+1]等于q; 如果a[l]=2,a[r+1]=1,那么区间[l,r+1]等于q; 如果a[l]=2,a[r+1]=2,那么区间[l+1,r+1]等于q-1。

Shift

首先如果把序列看作一个环,那么操作a就相当于旋转。考虑操作b,只会影响最前面的3个元素。通过操作b,我们可以实现将一个元素向前或向后移动1或2个位置。于是我们先固定n,然后将n-1移动到n前面,接下来是n-2,以此类推,直到只剩下2个数,然后分类讨论,如果已经排好了那就好了,否则如果n为偶数,可以通过不断将1往前移两个位置使其排好,否则的话就无解。

Plot

首先二分答案,然后贪心。判断一段是否合法可以用随机增量法求最小覆盖圆,如果一段的长度为l,那么求最小覆盖圆的时间复杂度是O(l)。考虑如何找到一段的右端点,如果直接二分,时间复杂度会有问题,所以我们先倍增找到右端点的范围,然后二分就行了。通过这题的卡常过程,我发现template的常数超大...

Strongbox

可以发现一定存在一个d,使得d的倍数都是答案,不是d的倍数的都不是答案。于是只要找到最小的d使得\(d\mid gcd(a[k],n)\)且$dgcd(a[i],n) (1i<k) \(。约数个数最大是17280,直接暴力的话是O(17280k)的,显然会超时。发现gcd(a[i],n)只有17280种取值,所以可以先去重,然后做到\)O(+klogk+17280^2)$。

Difference

枚举右端点,设R[i][j]表示当前前缀中i出现的次数与j出现次数之差,然后再维护L[i][j]表示之前出现过的i和j的最大差 如果不需要让出现次数最小的不为0,那么就可以直接统计答案了,但是这个题需要保证 所以维护最小值和与他出现次数不一样的次小值就可以了 注意右端点每窜一格R和L会变化的只有50个量,所以时间复杂度是O(50N)的

Garbage

可以证明如果存在方案,则存在一种方案满足每条边被经过最多一次,那么就是所有初始状态与最终状态不同的边都要经过一次,相同的边不经过。然后就把要经过的边加入图中,路径必须是简单环,dfs瞎搞一下就好了。

Tree Rotations

发现一个节点的两个儿子内部不管怎么交换,左儿子的所有节点总是要在右儿子的所有节点之前。所以只要决定谁作左儿子谁作右儿子就行了,且这样对于儿子内部的逆序对个数没有影响,所以只要每个节点都统计一下左儿子和右儿子中有多少对节点满足左边的比右边的小就行了。于是想到启发式,每次遍历小的那颗子树,询问另一颗子树中有多少个节点比它小就行了,可以用线段树维护,然后启发式合并就好了。

Temperature

枚举右端点,然后左端点显然是单调的,然后弄一个单调队列记录每天温度的下界,这样就可以知道这一段中最大的下界。右端点每右移一格,就把下界插入单调队列,将上界与队头比较,如果队头更大就出队。

Dynamite

先二分答案,然后树形dp就好了。

Party

对于任意两个点,如果他们之间没有边,那么他们之中至少有一个点不在团中,于是把这两个点都删掉。不断重复直到找不到这样的点,剩下的点形成一个团。

Inspection

DFS维护一堆东西就好了,POI居然也有这种无脑题...

Meteors

整体二分经典题就不说了

Sticks

按照长度枚举木棍,每个颜色维护长度小于等于当前长度的木棍中最长的,然后每次找到跟自己颜色不一样的最长的和第二长的就行了。

Programming Contest

经典的费用流做法会超时,考虑贪心,枚举时间1-t/r,每个人在不影响前面做的题的情况下尽量做题,发现匹配的时候肯定不会减少某人做的题的数目,所以直接匈牙利算法就好了。