一次艱難的優化Codeforces contest/810/problem/C

利用數學優化算法

這道題是一次我需要花一點時間來優化的題目,不然過不了。

給定n個各不相同的一維座標點 xi , 求所有F(a)的和,其中a是n個點的非空子集。若記A爲1到n的集合,則要求的是

aA,aF(a)

其中,F(a)是a中的所有點對之間距離的最大值。
F(a)=maxi,ja|xixj|

結果可能很大,對 109+7 取模。

輸入與數據範圍

第一行爲: n(1n3105)
第二行爲n個座標點 x1,x2,...,xn(1n109) . 所有xi 各不相同。

輸出

一個整數,求得的結果,模 109+7 .

分析與解

首先想到的暴力枚舉子集肯定是不行的。複雜度 O(2n) .

然後想預處理,可以先求兩兩座標之間的距離,然後可以排序,然後就可以按照從小到大的順序來看每個距離作爲最大值出現了幾次,就可以對每個距離的一個倍數求和,算上排序的時間複雜度 O(n2log(n)) 。但是這樣需要存儲 O(n2) 的距離,內存不夠。

然後結論是隻能用 O(n) 的內存來存座標點。

之後發現可以針對排序後的一對點 i 和 j (i<j,xi<xj) 得到 xjxi 這個距離需要加幾次,即有幾次作爲子集的最大值被加到結果裏。排序後,點i和點j之間的所有點組成的集合的子集a的F(a)都是 xjxi ,所以公式是

2(ji+1)2(xjxi)=2ji1(xjxi),i<j

這時我覺得可行於是就提交了。不過第一次錯誤是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的冪次的前綴和有關。公式是

presum_p2[0]=1,presum_p2[i+1]=presum_p2[i]+2i+1,i0

xi 需要被加和減的倍數則分別是

add_num=0,when i==1add_num=presum_p2[i2],when i2minus_num=presum_p2[ni1],when i<nminus_num=0,when i==n

因此可以預處理得到2的冪次的前綴和,時間複雜度O(n).
然後排序的時間複雜度 O(nlogn).
然後計算的時間複雜度 O(n).
總的時間複雜度 O(nlogn) , 存儲的空間複雜度 O(n).

然後提交又錯了,自己把輸入改成 scanf 而不用 cin 結果忘記加 cstdio 頭文件,本地又默認給我加上結果就沒發現,交了編譯錯纔看到,於是加上。

最終過了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章