传送门
怎么说呢(咳咳),貌似是一道结论题(博主并不知道结论呀,所以就FST抱灵了呀)。好吧博主承认没看到(k<2^{31})(相信没阿克的奆佬[除我]应该都RE在了这里)。测试成绩出来了,还好没有(k)极其之大的情况:)
先强调这里的({p_i})是排列。
仔细研读这个代码:
// 一轮交换
for i = 1 to n-1
if p[i] > p[i + 1]
swap(p[i], p[i + 1])
好像跟我刚学OI时的冒泡不一样耶
相邻的两项如果是逆序对就会进行交换。显然交换次数就是逆序对个数,不过这个没什么卯用。
再康康:发现如果一个数很大,比它后面的xx个数都要大,那么一顿排序猛如虎后,这个数会到达第一个比它大的数的前面,比如说({mathring4,1,2,3,5}),一轮排序后变成了({1,2,3,mathring4,5})。计(f_i)表示数字(i)所在位置前面比它大的数,那么逆序对总数就是(sum f_i)。这轮排序结束后,显然(f_i)只减不增,并且最多只会减一,就打这个例子,原本(f_1=f_2=f_3=1),之后就全变成了(0)。事实上由于前面最多有一个数字经过这个位置,且这个数字一定大于这个位置的数字,故最多只能使(f_i)减一,这个情况的发生必定有前面比它大的数字经过它。而又如果(f_i>0),则前面必定有比它大的数,其中一个数字一定会经过它,而且这个数字一定是前缀最大的数字(根据前文的推断,所有比这个数字小的都被“堵在”这个最大数字前面)。
把这些信息提炼出来就是:对于数字(i),排序过程中如果它所在位置前面有数字大于(i),那么一轮排序会使得前面最大的数字排到(i)的后面,这样(f_i)会减一。
综上,对于数字(i),其(f_i)在(k)轮排序后会变成(max{f_i-k,0})。
然后这道题就简单啦。维护(f_i),交换两个数相当于对(f_i)修改(本题的修改非常简单),对于查询,实际上就是求(sumlimits_{1leqslant ileqslant n}max{f_i-k,0}),我们可以运用差分,配上数据结构维护关于(k)的信息:前缀(f_i)和前缀(g_i=sumlimits_{1leqslant jleqslant n}[f_j==i])((g_i)即(f_j==i)的个数),然后查询答案对(f_i)进行差分再去掉(g_i)的差分乘上(k)即可。
复杂度( ext{O}(nlog n))。
为什么说(k)很坑?你如果做(2^{31}-1)次排序,再查查看(k)前缀(⊙o⊙)?!