NOI2019 回家路線(最短路,斜率優化)

2022-05-11 03:52:58 字數 2131 閱讀 4809

終於把這鬼玩意弄完了……

為什麼寫的這麼醜……

(順便吐槽 routesea)

最短路的狀態很顯然:\(f[i]\) 表示從第 \(i\) 條線下來的最小代價。

首先明顯要把那個式子拆開。直覺告訴我們這應該是個斜率優化。

\[f[i]=\min(f[j]+a(p_i-q_j)^2+b(p_i-q_j)+c)(x_i=y_j,p_i\ge q_j)

\]\[f[i]=\min(f[j]+ap_i^2-2ap_iq_j+aq_j^2+bp_i-bq_j+c)(x_i=y_j,p_i\ge q_j)

\]\[f[i]=ap_i^2+bp_i+c+\min((-2aq_j)\times p_i+(aq_j^2-bq_j+f[j]))(x_i=y_j,p_i\ge q_j)

\]後面是個明顯的斜率優化。(說是明顯然而同步賽時 sb 了居然沒看出來)

然而具體怎麼搞?我的**又臭又長或許就是在這裡……

我的做法是:把線按 \(p\) 排序,從小到大列舉。

每次把起點處的凸包能加線就加線,注意要加的 \(q\le\) 這條線的 \(p\)。由於 \(p\) 從小到大列舉這個很簡單。

然後在凸包上二分,把自己這條線加到終點的凸包的候選中。

不過由於我太菜,只想得到 set 維護凸包,所以寫得很醜。

然後因為有二分,又要對相鄰的線的交點再弄個 set……

無論如何時間複雜度 \(o(m\log m)\)。

#includeusing namespace std;

const int maxn=400040;

#define for(i,a,b) for(int i=(a);i<=(b);i++)

#define rof(i,a,b) for(int i=(a);i>=(b);i--)

#define mem(x,v) memset(x,v,sizeof(x))

inline int read()

struct edge

};struct point

void remove(int id,set::iterator it));

it1++;

} if(it2!=hull[id].end()) pt[id].erase((point));

if(it1!=hull[id].begin() && it2!=hull[id].end()));

} hull[id].erase(it);

}void insert(int id,item x)

if(it2!=hull[id].end())

it1=it2=it=hull[id].find(x);it2++;

if(it1!=hull[id].begin() && it2!=hull[id].end())

it=it1=it2=hull[id].find(x);it2++;

if(it1!=hull[id].begin() && it2!=hull[id].end()));

it1++;

} if(it1!=hull[id].begin()));

} if(it2!=hull[id].end()) pt[id].insert((point));

it=it1=hull[id].find(x);

while(it1!=hull[id].begin())

it=it1=hull[id].find(x);it1++;

while(it1!=hull[id].end()));

in[e[i].u].erase(in[e[i].u].begin());

} if(hull[e[i].u].empty()) continue;

int p=e[i].p,k,b;

set::iterator it=pt[e[i].u].lower_bound((point));

if(it==pt[e[i].u].end())

else k=it->k,b=it->b;

f[e[i].id]=a*p*p+b*p+c+k*p+b;

in[e[i].v].insert(e[i]);

if(e[i].v==n) ans=min(ans,f[e[i].id]+e[i].q);

} printf("%d\n",ans);

}

NOI2019 回家路線

點此看題 首先可以用暴力dpdp dp艹過去,設dp i j dp i j dp i j 為到了i ii點的時間是j jj的最小花費,由於時間是單向流逝的,我們可以先把邊按出發時間排序,用邊轉移,列舉到達出發點的時間jjj d p y i q i dp x i j cost p i j dp y i...

NOI2019 回家路線

link solution 演算法一通過觀察範圍發現 q leq1000 所以直接暴力拆點 dp 時間複雜度 o 1000m o 能過 演算法二因為有 a times x 2 b times x c 考慮斜率優化。設 f i 表示走完第 i 條邊的最小煩躁值,則 f i min space u i ...

LOJ 3156 NOI2019 回家路線

傳送門 明明可以bfs bfsbf s寫了個dij dijdi j把自己強行玩wawa wa有2種做法 第一種 考慮對於同乙個點的入邊i,j i,ji,j轉移給出邊xxx 把式子列出來後發現是乙個標準的斜率優化 在凸包上二分就可以了 複雜度o m logm o mlogm o mlog m 第二種 ...