【NOIP2018普及组】【DP】摆渡车
果然蒟蒻只會(huì)普及組的題…… ——ByChalotto——By\ \mathscr{Chalotto}——By?Chalotto
題目描述
有 nnn 名同學(xué)要乘坐擺渡車從人大附中前往人民大學(xué),第 iii 位同學(xué)在第 tit_iti? 分鐘去等車。只有一輛擺渡車在工作,擺渡車容量可以視為無限大。擺渡車從人大附中出發(fā)、把車上的同學(xué)送到人民大學(xué)、再回到人大附中(去接其他同學(xué)),這樣往返一趟總共花費(fèi) mmm 分鐘(同學(xué)上下車時(shí)間忽略不計(jì))。擺渡車要將所有同學(xué)都送到人民大學(xué)。
凱凱很好奇,如果他能任意安排擺渡車出發(fā)的時(shí)間,那么這些同學(xué)的等車時(shí)間之和最小為多少呢?
注意:擺渡車回到人大附中后即刻出發(fā)。
輸入格式
第一行包含兩個(gè)正整數(shù) n,mn,mn,m ,以一個(gè)空格分開,分別代表等車人數(shù)和擺渡車往返一趟的時(shí)間。
第二行包含 nnn 個(gè)正整數(shù),相鄰兩數(shù)之間以一個(gè)空格分隔,第 iii 個(gè)非負(fù)整數(shù) tit_iti? 代表第 iii 個(gè)同學(xué)到達(dá)車站的時(shí)刻。
輸出格式
輸出一行,一個(gè)整數(shù),表示所有同學(xué)等車時(shí)間之和的最小值(單位:分鐘)。
樣例輸入1
5 1
3 4 4 3 5
樣例輸出1
0
樣例說明
同學(xué) 111 和同學(xué) 444 在第 333 分鐘開始等車,等待 000 分鐘,在第 333 分鐘乘坐擺渡車出發(fā)。擺渡車在第 444 分鐘回答人大附中。
同學(xué) 222 和同學(xué) 333 在第 444 分鐘開始等車,等待 000 分鐘,在第 444 分鐘乘坐擺渡車出發(fā)。擺渡車在第 555 分鐘回到人大附中。
同學(xué) 555 在第 555 分鐘開始等車,等待 000 分鐘,在第 555 分鐘乘坐擺渡車出發(fā)。自此所有同學(xué)都被送到人民大學(xué)。總等待時(shí)間為 000 。
樣例輸入2
5 5
11 13 1 5 5
樣例輸出2
4
樣例說明
同學(xué) 333 在第 111 分鐘開始等車,等待 000 分鐘,在第 111 分鐘乘坐擺渡車出發(fā)。擺渡車在第 666 分鐘回答人大附中。
同學(xué) 444 和同學(xué) 555 在第 555 分鐘開始等車,等待 111 分鐘,在第 666 分鐘乘坐擺渡車出發(fā)。擺渡車在第 111111 分鐘回到人大附中。
同學(xué) 111 在第 111111 分鐘開始等車,等待 222 分鐘;同學(xué) 222 在第 131313 分鐘開始等車,等待 000 分鐘。他/她們?cè)诘?131313 分鐘乘坐擺渡車出發(fā)。自此所有同學(xué)都被送到人民大學(xué)。總等待時(shí)間為 444 。可以證明,沒有總等待時(shí)間小于 444 的方案。
數(shù)據(jù)規(guī)模與約定
對(duì)于 10%10\%10% 的數(shù)據(jù), n≤10,m=1,0≤ti≤100n\le 10,m=1,0\le t_i\le 100n≤10,m=1,0≤ti?≤100 。
對(duì)于 30%30\%30% 的數(shù)據(jù), n≤20,m≤2,0≤ti≤100n\le 20,m\le 2,0\le t_i\le 100n≤20,m≤2,0≤ti?≤100 。
對(duì)于 50%50\%50% 的數(shù)據(jù), n≤500,m≤100,0≤ti≤104n\le 500,m\le 100,0\le t_i\le 10^4n≤500,m≤100,0≤ti?≤104 。
另有 20%20\%20% 的數(shù)據(jù), n≤500,m≤10,0≤ti≤4×106n\le 500,m\le 10,0\le t_i\le 4\times 10^6n≤500,m≤10,0≤ti?≤4×106 。
對(duì)于 100%100\%100% 的數(shù)據(jù), n≤500,m≤100,0≤ti≤4×106n\le 500,m\le100,0\le t_i\le 4\times 10^6n≤500,m≤100,0≤ti?≤4×106 。
?解析?
顯然證明法就是根據(jù)題目的意思進(jìn)行直覺性判斷,從而證明結(jié)論成立。
顯然,這是一道 DPDPDP 題。
于是設(shè) f[i]f[i]f[i] 表示第 iii 分鐘發(fā)出一輛車所要的最小時(shí)間,設(shè) ttt 為最后一個(gè)人到達(dá)車站的時(shí)間。
得到狀態(tài)轉(zhuǎn)移方程:f[i]=min{f[k]+∑k<a[j]≤ii?a[j]}(0≤k≤i?m)f[i]=min\{f[k]+\sum_{k<a[j]\le i}i-a[j]\}(0\le k\le i-m)f[i]=min{f[k]+k<a[j]≤i∑?i?a[j]}(0≤k≤i?m)其中 kkk 表示上一輛末班車回來的時(shí)間。
那么最后的答案即為:ans=min{f[i]}(t≤i<t+m)ans=min\{f[i]\}(t\le i<t+m)ans=min{f[i]}(t≤i<t+m)
i<t+mi<t+mi<t+m 是因?yàn)樽詈笠粋€(gè)人等的時(shí)間不會(huì)超過 mmm 分鐘,不然他可以直接乘之前的一輛走,肯定不是最優(yōu)解。
時(shí)間復(fù)雜度: Θ(t2n)\Theta(t^2n)Θ(t2n)
優(yōu)化
1、前綴和優(yōu)化
令 cnt[i]cnt[i]cnt[i] 表示到 iii 為止到達(dá)車站的人數(shù)和
sum[i]sum[i]sum[i] 表示到 iii 為止到達(dá)車站的人的時(shí)間總和
顯然有:∑k<a[j]≤ii?a[j]=i?(cnt[i]?cnt[k])?(sum[i]?sum[k])\sum_{k<a[j]\le i}i-a[j]=i*(cnt[i]-cnt[k])-(sum[i]-sum[k])k<a[j]≤i∑?i?a[j]=i?(cnt[i]?cnt[k])?(sum[i]?sum[k])即,總等待時(shí)間 === i×(i~ki\times (i\sim ki×(i~k 內(nèi)總?cè)藬?shù)))) ?-? 等待時(shí)間在 i~ki\sim ki~k 內(nèi)所有人的等待時(shí)間之和。
附上一張圖幫助理解:
于是方程變?yōu)?#xff1a;f[i]=min{f[k]+i?(cnt[i]?cnt[k])?(sum[i]?sum[k])}(k≤i?m)f[i]=min\{f[k]+i*(cnt[i]-cnt[k])-(sum[i]-sum[k])\}(k\le i-m)f[i]=min{f[k]+i?(cnt[i]?cnt[k])?(sum[i]?sum[k])}(k≤i?m)
時(shí)間復(fù)雜度:Θ(t2)\Theta(t^2)Θ(t2)
2、轉(zhuǎn)移優(yōu)化
顯然,沒有一位同學(xué)的等待時(shí)間會(huì)超過 2m2m2m 分鐘。
簡(jiǎn)單證明:
考慮最壞的情況,在 kkk 時(shí)刻發(fā)了一輛車,有個(gè)同學(xué)在 k+1k+1k+1 時(shí)到達(dá)車站,那么擺渡車將在 k+mk+mk+m 時(shí)返回,考慮到等待其它學(xué)生的情況,擺渡車最晚會(huì)在 k+2m?1k+2m-1k+2m?1 時(shí)發(fā)車,否則還不如分別在 k+mk+mk+m 和 k+2mk+2mk+2m 的時(shí)候發(fā)出。
所以, kkk 的范圍就變?yōu)?#xff1a; i?2m<i≤i?mi-2m<i\le i-mi?2m<i≤i?m 。
時(shí)間復(fù)雜度: Θ(tm)\Theta(tm)Θ(tm)
完全不用虛了(??????‵)
代碼展示
#include<bits/stdc++.h> #define ll long long #define me(x) memset(x,0,sizeof(x)) #define bi(x) memset(x,0x3f,sizeof(x)) #define ud using namespace std ud; const int maxn=1e7+10; int last_time=-9876543,ans=1<<30; int N,M,t[maxn],f[maxn],sum[maxn]={},cnt[maxn]={}; inline long long read() {long long s=0,f=1; char ch; for(;ch<'0' || ch>'9';ch=getchar()) if(ch=='-') f=-1;for(;ch>='0' && ch<='9';ch=getchar()) s=(s<<1)+(s<<3)+ch-'0'; return s*f; } int main() {N=read(),M=read();for(int i=1;i<=N;++i) {t[i]=read();// Find the last person who reach the stationlast_time=max(last_time,t[i]);++cnt[t[i]];//從0到i時(shí)間為止到達(dá)車站的人數(shù)和sum[t[i]]+=t[i];//從0到i時(shí)間為止到達(dá)車站的人的時(shí)間總和}for(int i=1;i<last_time+M;++i){cnt[i]+=cnt[i-1];sum[i]+=sum[i-1];}for(int i=0;i<last_time+M;++i){if(i>=M&&cnt[i-M]==cnt[i]){f[i]=f[i-M]; continue;}f[i]=cnt[i]*i-sum[i];for(int j=max(i-(M<<1)+1,0);j<=i-M;++j)f[i]=min(f[i],f[j]+(cnt[i]-cnt[j])*i-(sum[i]-sum[j]));} for(int i=last_time;i<last_time+M;++i) ans=min(ans,f[i]);printf("%d\n",ans);return 0; }總結(jié)
以上是生活随笔為你收集整理的【NOIP2018普及组】【DP】摆渡车的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NOIP 2018【摆渡车】题解
- 下一篇: 【NOIP2018普及组】摆渡车