模拟31 题解

A. math

考试时打的错解,
取每个$a_i$与k的gcd,分别做背包由0直到k。
但是复杂度有点问题,于是做了个筛。
$O(k sqrt(k))$一定没有问题,在不构造特殊数据下很优秀。
考后突然被自己一个简单的数据hack掉了。
2 6
2 3
我的程序会输出
5
0 2 3 4 5
然而显然1是可以被拼凑出来的。
正解是求出k与所有的$a_i$的gcd。
答案就是k/gcd,
和首项为0,末项小于k的公差为gcd的等差数列。
正确性是显然的。


B. biology

将所有的坐标放进结构体里,
以a值排个序,
直接$O(n^4)$暴力dp。

把它优化成$O(n^2)$或者$O(n^2logn)$就可过。
观察第三个部分分,得到一个性质:
一行可以只由它的前一行转移过来。
原因是b值不为负,而另一项为两点之间的距离。
多走一次不会使答案变差。
继续观察得到另一个性质:
将两点距离中的横纵坐标拆开,
即将$abs(x1-x2)+abs(y1-y2)$拆为类似$(x1+y1)-(x2+y2)$的四种形式。
可以将不好维护的两点距离转化掉。
只需知道每个点四个方向上的最大值即可。
二维树状数组可维护,复杂度$O(n^2log^2n)$。

为什么要关注确切的方向?
按照事实考虑确实是需要的。
在天使玩偶一题中,要求最小值。
如果我们错误的选择了方向,可能会使本应取正的abs值取了负,使答案更小,也就错了。
但本题中视答案更大为更优。
如果做出一些可能会使答案更小的操作,是不影响最终答案的。
于是直接把维护树状数组改成维护四个变量就可以了。
这个题在考场上做的很坎坷,一点点把暴力的dp,拆成了恶心的数据结构,最终又化回了很简单的形式。



C. english

题中要求的区间比较难处理,
显然枚举最大值在哪,找到它决策的左右区间。
第一问一眼切了。
异或显然按位处理,处理出每一位上1的个数的前缀和来区间查找。
枚举最大值,只有0^1可得1,直接区间查找就完了。

第二问还复杂一些,
因为要统计方案数,显然维护trie树。
要查询区间,可持久化啊,还不是很难打。
仍然是枚举最大值,
如果最大值左侧区间比较短,就枚举左侧区间上的数,查询右侧区间。
反之则枚举右侧区间上的数,查询左侧区间。
考场上实在是想不出来如何构造数据卡掉这个算法(实际上确实没有),就打了出来。

复杂度的证明用了轻重儿子的思想。
首先应当注意一些性质:
求出的左右区间,必定满足
$a[i]<a[l[i]-1]$
$a[i]<a[r[i]+1]$
任取i的决策区间中的j,
$a[j]<a[i]$
使初始区间为(1,n),不断找区间中的最大值,向左右递归,可以形成一棵二叉树。
所以我们的算法就是不断枚举轻儿子查询重儿子。
显然复杂度为$O(nlognlogmx)$。
最坏情况是一棵完全二叉树。

如果想到了正解的思想,
也可以直接建树找轻重儿子,用启发式合并trie树做这一道题。
posted @ 2019-08-25 07:01  skyh  阅读(257)  评论(2编辑  收藏  举报