hihoCoder Challenge 19 题解 by jiry_2

14
5

A

直接暴力DP的状态数是O(n*4^12)的,这样会超时。

我们可以对每一个二进制位记录一个值,当这个值为2的时候,表示所有选出来的数中,这一位都是1;对于其它情况,如果选出来的数有奇数个1,那么值为1,否则就为0。

不难发现按照上述状态进行DP,只要再记录一下选出来的数的个数的奇偶性,就能从状态中直接得到选出来的所有数的异或值和and和,这样状态数就缩减到了O(n*3^12),就能过了。

B

先把所有数从小到大排序,接着可以枚举中位数是哪两个数的平均数,假设是l和r(长度为奇数的情况相当于l=r),然后我们给数列中所有数减去平均数,那么这时的方案数就等于从[1,l),(r,n]这两个区间中选出相同数目的数使得它们的和小于0。

我们可以把待选的数给单独拿出来(即把区间[l,r]的数删掉),如果原来它的下标小于l,把么权重为1否则权重为-1。问题就相当于给出若干个数,你要选出一些数使得它们的权重和为0且权值和小于0,这是一个经典的meet in middle的问题。我们可以把数均等的分成两部分,分别处理出两部分中的所有选取方法,然后根据权重分组,每组排序之后就能统计答案了。

上述算法的时间复杂度是
<code>\sum_{i=1}^n (n-i)*2^{(n-i)/2}\*(n-i)/2=O(2^{n/2}*n^2)</code>
这样是会超时的(除非你的常数足够好)。

我们发现我们没有必要排序,我们可以在枚举的时候使用归并的方法,直接让每组有序,这样就能减少一个n的复杂度。

C

显然如果一张子图的权值不是0,那么在这张子图中最多只有一个简单环。

考虑没有环的情况,我们要统计的就是这张图的所有生成森林的权值和。统计最小生成树个数有一个传统的基尔霍夫矩阵的做法,不难发现只要添加一个虚点,往所有节点都连一条边,那么新图的最小生成树个数就是原图所有生成森林的权值和。

现在考虑恰好有一个环的情况,这也是一个经典问题,我们可以先枚举环上的点集。一个点集组成一个环的方案数可以用一个O(2^nn^2)的DP求出,接着我们可以把这个环缩成一个点,然后就转化成生成森林的问题了(注意在缩成点之后新增加的虚点要向这个位置连环的大小条边)。

时间复杂度O(2^nn^3)

D

可以参考WC2016上的营员交流《segment tree beats》,在这个上面介绍了一种把区间取max,区间取min操作转化成区间加减操作的方法(但是上面的复杂度分析略有问题)。

考虑只有区间加减,显然被影响到的区间中的所有数都被修改了(要注意特判加0的情况),只需要区间加一就行了。

所以现在我们可以在线段树上把最小值、最大值、同时不是最大值和最小值这三类数分开来统计,要注意在边界情况下可能会有一些细节问题。

时间复杂度O(mlog^2n)

  • A题能否贴份代码链接。。 好理解些。。rank榜出题的代码并看不懂。。

  • 添加评论
  • reply

15 answer(s)

1

Orz, 这个网站果然大牛很多啊。 上两次的练习赛就看出来了,随随便便全部AC

0

哦我似乎明白了T4复杂度的证明,最坏复杂度自然是mnlog^2n的 但是实际上是绝对不可能那么慢的 因为,我们对一些不同的数进行了一个max或者min操作之后,实际上等同于缩点,因为他们变成一样的了! 而维护的最大值或者最小值的数量直接使这么多个点变成了一个! 实际上复杂度仍然是那么多但是越到后面n会越小 如果数据每次缩掉的点不多说明dfs的深度也很浅 于是这题实际上不能用大O表示法来看多快,应该用T来表示 好了再次暴力膜吉利大神 好了以上纯属瞎BB

0

D题的B线段树如何处理,我们只知道A线段树中哪一个区间被改了哪一些,但是我们不知道B线段树中这个区间的两个子区间应该分别加上多少?请问这个怎么处理?

  • 你可以看《segment tree beats》这个课件,上面有介绍这一类问题怎么处理

  • 呀不不不,我明白了那个课件的做法了,有点不清楚的地方在于我们需要维护第二棵线段树吗?还是说是同一颗线段树?感觉分开两颗没办法维护

  • 话说复杂度证明有问题的话是标记回收那一块?那复杂度究竟是多少?还是说能hack掉?

  • 总觉得这题最坏复杂度是mnlog^2n的

  • 添加评论
  • reply
0

出题人好屌

0

觉得第一题复杂度是O(n^2*3^13),因为不记录前面取了几个数,即使知道某位全是1也不知道有几个1,请大牛们鉴定

  • 题解上说了,记录前面取了多少个数,只要知道个数的奇偶就行了,所以用2个状态就可以记录。复杂度为O(2*n*3^13)

  • 添加评论
  • reply
0

表示T1写了正解发现本机要10s。。

  • 你是不是转移不是O(1)?

  • 我只是把状态算成数组需要O(13)

  • 强行转移O(1)貌似挺麻烦的啊。表示蒟蒻位运算式子写完已懵逼。

  • 你可以预处理出每个状态对应的四进制啊。。然后不就O(1)了吗。。不然你不是做了n遍进制转换么

  • 写了个n^2*3^13的正解,然后T了,悲剧

  • 有谁按照标程写的吗,给大家参考一下

  • @wuzhengkai 我这么做A了,谢谢

  • @dx911127 我发讨论里了

  • 添加评论
  • reply
1

orz,想问这场是啥难度,省选,NOI 吗?= =

0

orzzzzzzz

1

哎……

0

orz 太弱了

0

火前orz

0

orz

2

orz

3

orz

1

n*4^12的暴力dp是什么意思……

  • 出题人当我们是大犇

  • orz出题人

  • 直接开dp[i][j][k]表示当前的位置,异或和和and值

  • jiry_2你那复杂度怎么算的,吓傻了

  • 哪题啊

  • A题 O(m*3^12) 的m哪来的。。。是n吗

  • 啊..哪里有m

  • 12是我忘记更新题解了,应该是13

  • 添加评论
  • reply

write answer 切换为英文 切换为中文


转发分享