日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

摆渡车(noip2018 pj t3)

發(fā)布時間:2023/12/2 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 摆渡车(noip2018 pj t3) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

擺渡車(題目和測試右轉 洛谷P5017)

做法:dp+各種優(yōu)化(剪枝)

這道題考場上看了一臉懵逼...第一眼看這 tm 不是個一維dp嗎...結果按著這個朦朧的思路,刪刪改改約莫0.5h,終于過了樣例,然后一測大樣例...GG了。冥思苦想了1h,最終放棄了 (感謝這白費的1.5h,迫使我T4打了個暴力,結果AC了...

言歸正傳

考試完后,參考了各種題解,WA了N/A次,終于AC了這道毒瘤題,艱難的AC歷程...

(〇)引子

首先來闡明一下題意:在一條數(shù)軸上有n個點,然后要求將這條數(shù)軸分為若干段(左開右閉的區(qū)間),要求:每段的兩個端點之間的距離必須 >= m,求分段的最小總費用。

費用定義為:若一個點k在區(qū)間 ( j , i ] ,則這個點的費用為 i - k (可能一個位置上有多個點)

總費用定義為:所有點的費用和即為總費用

?

(一)如何拿分(暴力?)

講解完題意,接下來我們要研究一個很重要的問題:如何拿分?

先看 30% 的數(shù)據(jù):

n20, ?m2, ?0ti?100

看著 ti 的大小很容易想到用一維數(shù)組 f[i] 表示在第 i 分鐘發(fā)車的最小費用。

然后,這TM不是個一維線性dp嗎?

我們可以枚舉一個 j ,即枚舉前一次是在哪里發(fā)車的,這樣我們便得到了狀態(tài)轉移方程:

這樣一來,時間復雜度就是 ?,30%的數(shù)據(jù)是可以過的。

?

(二)如何拿中分(不高也不低的分

看一下50%的數(shù)據(jù):

n ≤ 500, ?m ≤ 100, 0 ≤ ti ≤ 10^4

nt^2的時間復雜完全過不了50%得數(shù)據(jù),怎么辦呢

通過觀察(一)的狀態(tài)轉移方程,可以發(fā)現(xiàn)枚舉一個k實際上是沒必要的,可以用前綴和優(yōu)化:

將等車人到達的時間用數(shù)組存起來,peo[ i ]表示在 0 到 i 分鐘內等車人的數(shù)量,cost[ i ]表示在 0 到 i 分鐘所有等車人到達時間的累積(即將 1 到 i 分鐘內到達的等車人的到達時間累加起來)

就可以得到狀態(tài)轉移方程

分析一下時間復雜度:因為只枚舉了 i 和 j ,所以時間復雜度降低為

50%的數(shù)據(jù)在 “少爺機” 上是穩(wěn)穩(wěn)的。

程序段:

?

1 for(int i=1; i<t+m; i++) 2 { 3 f[i] = i*peo[i] - cost[i]; 4 for(int j=0; j<=i-m; j++) 5 f[i] = min(f[i], f[j]+(peo[i]-peo[j])*i-(cost[i]-cost[j])); 6 }

?

?

?

?

(三)如何拿高分(不是滿分,考場上的高分

自然是優(yōu)化啦。問題來了,如何優(yōu)化。

先看看70%的數(shù)據(jù)范圍:

n500,?m10,?0ti?4×10^6

很明顯,t^2的時間復雜的是肯定超的。而 i 是這個狀態(tài)轉移方程的狀態(tài),必須要枚舉,只能從 j 下手,優(yōu)化這個動態(tài)規(guī)劃了。

j 如何優(yōu)化呢?其實,仔細想一想,很容易發(fā)現(xiàn),j 沒有必要從 0 枚舉到 i-m,換句話說,從0到 i-m 的這段區(qū)間內,有很多狀態(tài)是無用的,即這些狀態(tài)一定不能構成當前 f[i] 的最優(yōu)解,真正有用的只有區(qū)間 ( i-m-m+1, i-m ]。如何證明呢?

先貼一幅圖:

?

觀察上圖可以發(fā)現(xiàn):

當 j 在 ( R, i )中時,擺渡車回來的時間一定大于 i ,不滿足狀態(tài) f[i] 的定義,舍去。

當 j 在 ( ?, L ]中時,一定可以多發(fā)一次車,使擺渡車回來的時間小于等于 i,這樣得到的花費一定小于等于只發(fā)一次車的情況。因此,也可以省去。

最后,我們發(fā)現(xiàn),j 只能在區(qū)間 ( L, R ] 之間才能得到最小花費,即 j 只有 m-1 種情況

于是,狀態(tài)轉移方程不變,j 的枚舉范圍改變,時間復雜度降為

70%的數(shù)據(jù)穩(wěn)穩(wěn)地過,甚至在 “少爺機” 上面的 score 可能 100 ( 最起碼分數(shù)在70以上 )。

程序段:

?

1 for(int i=1; i<t+m; i++) 2 { 3 f[i] = i*peo[i] - cost[i]; 4 for(int j=max(i-m-m+1,0); j<=i-m; j++) 5 f[i] = min(f[i], f[j]+(peo[i]-peo[j])*i-(cost[i]-cost[j])); 6 }

?

?

(四)70+太低了如何拿滿分

老樣子,再來看一下數(shù)據(jù)范圍(終極boss來了):

n500,?m100,?0ti?4×10^6

m的范圍變回 100 了,tm的時間復雜度好方,腫么辦!!!

別著急,先來分析一下數(shù)據(jù)范圍:

可以發(fā)現(xiàn),ti 達到了4*10^6 ,然鵝 n 卻還是500,不難想象,如果將 ti 看做一條線段,上面有 4*10^6個整點,然后取其中的500個點標記,標記的點一定是非常離散的。

?同樣的道理,在如此之大的 ti 中,一定有很多區(qū)間是沒有等車人的(無用的區(qū)間),但是仍然無用地枚舉了m次,時間復雜度大大增加。

這時候,我們只需要加一個小小的剪枝,判斷當前枚舉的 i 點到 i-m 中是否有人,如果沒有人的話,就沒有必要進行多一次的循環(huán)了(因為再發(fā)多一次車對答案沒有影響,畢竟沒人),只需要將 f[i] 賦值為 f[i-m],然后continue即可。

經(jīng)過某神犇的證明,經(jīng)過這次剪枝后,實際枚舉的點只有 nm 個,時間復雜度降為(當然還有一個常數(shù) t 被我忽略了)

100%的數(shù)據(jù)跑得飛快……

程序段:

?

1 for(int i=1; i<t+m; i++) 2 { 3 if(i>=m and peo[i]-peo[i-m] == 0) {f[i] = f[i-m]; continue;} 4 f[i] = i*peo[i] - cost[i]; 5 for(int j=0; j<=i-m; j++) 6 f[i] = min(f[i], f[j]+(peo[i]-peo[j])*i-(cost[i]-cost[j])); 7 }

?

?

(五)答案在哪?

終于到最后一步了,顯而易見,answer一定在最大的時間后面(廢話),只需要從 t 枚舉到 t+m-1 取一個最小值即可。

注意:

代碼中的 t 和 (五)中的 t 含義相同,都是最后到的那個人的到達時間。

?

ps:終于寫完了,這個思路是參考了某神犇的(@Sooke),再加上了自己的一些理解,希望能有幫助。

?

轉載于:https://www.cnblogs.com/GDOI2018/p/9994768.html

總結

以上是生活随笔為你收集整理的摆渡车(noip2018 pj t3)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。