题目描述
有一组无序序列,a1,a2,⋯,an,你现在可以多次的交换任意一对(ai,aj),也就可以对序列重新进行排序,形成新的序列b1,b2,⋯,bn,设preSum(k)=∑i=1kbi,也就是bi的前缀和,现在求使∑i=1npreSum(i)最小的序列,也就是使前缀和的前缀和最小的b序列
样例输入
样例输出
数据范围
n⩽106
解法0: 暴力枚举
直接全排列枚举,找到最小的那个序列,
时间为n!⋅n,最后乘n,因为每一次排列后求序列和是O(n)的
代码如下
你可能会说:会超时,这个算法没用.
但是!,你运行上面的代码,观察输出数据,你一定能发现规律?
- 这个题目出现在这里,所以这个题目是解的(非NPC问题),所以必然存在一个方法,设为Ψ,可以解这个问题
- Ψ这个解法的时间复杂度是多少呢?显然根据n⩽106,要么是O(n),要么是O(nlog2n)
- 根据做题目的经验,如果是O(n)的,就是扫一遍,就出来了
- 如果是n⋅log2n,那么你学过哪些log2n或nlog2n的算法?
总结,我们做题目一定有规律,只是大部分时候,这些规律是无法用肉眼观察到.
但是可以用题目的数据范围来推测出解的时间复杂度,然后根据复杂度,来猜,是一个什么样的规律,或使用的是什么算法,当然这需要做题目经验
- O(1),存在数据公式
- log2n,和有序相关的算法或数据结构
- n2,二重循环
- n<10
解法1
使用特例法,方法Ψ显然可以解下面的这些特殊的例子
0 0 0 0 0,全是0
x x x x x,全是同一个数x
x x x x x very-big-number,有一个超大的数,其它数都一样
x x x x x big-number very-big-number,有两大数,其中一个非常大,其它数都一样
解说…TODO
对于情况1,2,显然无论怎么交换,得到的结果都一样.所以不需要任何操作
对于情况3,直觉的想法就是把very-big-number放最后面,
对于情况4…
有一个直觉的想法,大的数应该放后面,因为后面的加的次数少
公式验证如下
preSum(1)b1preSum(2)b1+b2preSum(3)b1+b2+b3⋯preSum(n)b1+b2+b3+⋯+bn得到公式
Sum(b)=n⋅b1+(n−1)⋅b2+⋯+bn总结: 解法的核心思想:特例法,一步一步使例子变的混乱,只要数据够特别,题目就会变得简单,接题目的要求.
解法2
序列B如下
b1,b2,⋯,bi,bi+1,⋯,bn设此时序列B得到的结果为
S1=preSum(1)+preSum(2)+⋯+preSum(n)此时交换bi,bi+1得到序列C如下,和设为S2
b1,b2,⋯,bi+1,bi,⋯,bn发现此时只有preSum(i),preSum(i+1)的值改变,其它的preSum没有改变,
其时上面那句话有误,应该只有preSum(i)产生了变化
显然
S2−S1=preSumB(i)+preSumB(i+1)−preSumC(i)−preSumC(i+1)=(preSumB(i)−preSumC(i))+(preSumB(i+1)−preSumC(i+1))=(bi−bi+1)+0=bi−bi+1显然
- 若bi=bi+1,则B和C一样大
- 若bi<bi+1,则B比C小
- 若bi>bi+1,则B比C大
综上,若一个序列B交换相邻的两个值bi,bi+1,bi>bi+1,也就是把大的数放后面,小的放前面,可以得到一个具有更小和的序列C,同样,容易想到,C也可以用这种方法,得到更小的序列.那么这样一直迭代下去
我们证明的这个东西,在数学上叫做排序不等于式 TODO 上标
简写如下
对于任何一个序列,都有
正序和⩽乱序和⩽逆序和
解法
f(A)=i=1∑nai+f(A−{an})可以想到∑i=1nai是定值,所以要找出最小的f(A−{an})值
问题就变成了去除哪个元素后子集合B=A−{ai},B⊂A的值最小?
设如果(ai,aj),其中ai∈/B,aj∈B,也就ai是去除的元素,aj是没有去除的元素,可以想到,分情况讨论
产生了两个子集
- B1=A−{ai},也就是B1不包含ai
- B2=A−{aj},也就是B2不包含aj
- ai=aj,此时,f(B1)=f(B2)
- ai<aj,此时,f(B1)=f(B2)
如果存一处排列在B1,得到f(B1),那只要把序列中aj替换成ai,就得到了一个新的序列,由集合B2中元素组合,且一定f(B2)<f(B1)
由此,只要存一对数(ai,aj),ai<aj,就可以得到一个更小的f(A−{an})
数学描述如下
TODO 下面的这个推导好像不对,到少感觉不合适
∃i∃j(ai<aj)→f(Bi)<f(Bj),ai∈Bi∧aj∈Bj∧Bi−{ai}=Bj−{aj}
按种逻辑推导,什么情况下可以,得到最小的f(A−{ai})
删除一个数,就是会得到一个集合B
最后应该推导出一个结论,删除最大的那个数,应该是最小的
总结: 如果进行定位集(集合中的每个元素在最终答案里都有对应的固定位置)的集合分类?
解法
选一个数放最前面,
f(A)=n×ai+f(B),B=A−{ai}
这个不好考虑了,
因为n×ai 与f(B)都是变化量
总结
ref