利用数学优化算法
这道题是一次我需要花一点时间来优化的题目,不然过不了。
给定n个各不相同的一维坐标点
xi
, 求所有F(a)的和,其中a是n个点的非空子集。若记A为1到n的集合,则要求的是
其中,F(a)是a中的所有点对之间距离的最大值。
结果可能很大,对 109+7 取模。
输入与数据范围
第一行为:
n(1≤n≤3∗105)
第二行为n个坐标点
x1,x2,...,xn(1≤n≤109)
. 所有
xi
各不相同。
输出
一个整数,求得的结果,模 109+7 .
分析与解
首先想到的暴力枚举子集肯定是不行的。复杂度 O(2n) .
然后想预处理,可以先求两两坐标之间的距离,然后可以排序,然后就可以按照从小到大的顺序来看每个距离作为最大值出现了几次,就可以对每个距离的一个倍数求和,算上排序的时间复杂度 O(n2log(n)) 。但是这样需要存储 O(n2) 的距离,内存不够。
然后结论是只能用 O(n) 的内存来存坐标点。
之后发现可以针对排序后的一对点 i 和 j
(i<j,xi<xj)
得到
xj−xi
这个距离需要加几次,即有几次作为子集的最大值被加到结果里。排序后,点i和点j之间的所有点组成的集合的子集a的F(a)都是
xj−xi
,所以公式是
这时我觉得可行于是就提交了。不过第一次错误是compilation error,因为调用 algorithm 的 sort 没有包含 algorithm 头文件,而我本地的编译器是自动支持的。再次提交在第六个点出错,wrong answer。仔细检查发现是预处理求2的幂取模的部分出错,取模用的存2的幂的变量是有符号的时候一直乘以2再取模就有问题,换成 unsigned int 之后过了第6个点。
但是第8个点开始超时。乍开始以为是初始化用的是 vector< int >(n, 0) 导致的,但是改成全局数组之后提交还是超时。
改回思考算法,发现复杂度是
O(n2)
的还是太高了。300000 个数据跑不完。只能再想
O(n)
算法。
经过观察发现之前的计算方法可以直接计算出每个坐标
xi
分别被加了几次减了几次,次数与2的幂次的前缀和有关。公式是
而 xi 需要被加和减的倍数则分别是
因此可以预处理得到2的幂次的前缀和,时间复杂度O(n).
然后排序的时间复杂度 O(nlogn).
然后计算的时间复杂度 O(n).
总的时间复杂度
O(nlogn)
, 存储的空间复杂度 O(n).
然后提交又错了,自己把输入改成 scanf 而不用 cin 结果忘记加 cstdio 头文件,本地又默认给我加上结果就没发现,交了编译错才看到,于是加上。
最终过了。