狡猾的商人

2022-01-30 06:52:33 字數 1948 閱讀 7461

洛谷p2294 [hnoi2005]狡猾的商人

前言大概一定是我太蒻了,卡在這道題的差分約束做法上卡了幾個小時qaq

在摸差分約束做法前,得出了類似於這位dalao題解的思路,可惜因為沒想到優先佇列而選擇了\(vector\),所以沒有實現(在看了題解之後獨自編出來了,會具體講解)

做法(對優先佇列那種神奇做法不感興趣的可以直接跳過看差分約束做法)

優先佇列

還是算有點貪心+模擬的思路吧?因為這種做法好像沒名字(傳說中的玄學孤兒演算法qwq)

先來分析一波兩個樣例(直接見圖即可):

所以,我們可以得出一種解決方法:

先將輸入的區間按規則排序,然後依次比較前後兩個區間,遇到左端點相等的就推出另乙個式子壓入待處理判斷的陣列中,如果有兩個式子相矛盾就直接輸出\(false\),否則最後輸出\(true\)

排序規則:左端點相等則右端點小的在前,否則按左端點小的排在前

這裡我們需要思考一下,因為是前後兩個區間比對,所以我們每壓入乙個新的式子都要進行如上排序。那怎麼實現?直接\(sort\)肯定是會超時的

在看了最上面那篇題解後,恍然大悟:直接用過載的優先佇列啊!

至於時間複雜度的證明,我也不會,但是優先佇列確實比\(sort\)跑得快

放上**:

#include using namespace std;

int t,n,m;

struct node

} a;

priority_queueq;

int main()

node fir=q.top();

q.pop();

// cout差分約束系統

不了解差分約束系統的珂見這篇部落格啊qwq 無恥

我們首先需要確定的是這題跑最短路還是最長路

我個人偏向於跑最長路(因為跑最短路似乎也能a?)

為什麼是最長路?因為在差分約束系統中跑最長路得到的是最小解(不懂的就上面的鏈結吧ovo),且如果最小解都滿足了那大一點的解肯定也滿足

那本題的約束條件是什麼?直接是輸入中的\(t-s=v\)嗎?

當然不是!轉換一下思路,從\(s\)到\(t\)的總收入可以用字首和表示:\(sum[i]\)表示\(i\)月之前的所有月收入的總和

約束條件則是\(sum[t]-sum[s-1]=v\)!

再轉換上面那個式子,就得到如何建邊:

\(sum[t]-sum[s-1]≥v\),所以從\(t\)到\(s-1\)連一條權值為\(v\)的邊

\(sum[t]-sum[s-1]≤v\),所以從\(s-1\)到\(t\)連一條權值為\(-v\)的邊

然後就是正常的跑差分約束系統的最長路板子了(這裡採用全部入隊的方式,而不是使用超級源點)

**如下:

#include using namespace std;

int t,n,m,u,v,w,tot;

int dis[250010],vis[250010],cnt[250010],head[250010];

struct node e[250010];

inline void add(int u,int v,int w)

inline bool spfa()

while(!q.empty()) {

int x=q.front();

q.pop();

vis[x]=0;

for(register int i=head[x];i;i=e[i].net) {

int v=e[i].to;

if(dis[v]然後,感謝一些同桌對我程式的修改

狡猾的商人 題解

題目描述 刁奼接到乙個任務,為稅務部門調查一位商人的賬本,看看賬本是不是偽造的。賬本上記錄了n個月以來的收入情況,其中第i 個月的收入額為ai i 1,2,3.n 1,n 當 ai大於0時表示這個月盈利ai 元,當 ai小於0時表示這個月虧損ai 元。所謂一段時間內的總收入,就是這段時間內每個月的收...

bzoj1202 狡猾的商人

如果這個賬本是真的話,那麼對於乙個s,t,在圖上,兩個點之間任意一條路徑的長度都必須相等,不然這個賬本就不是真的。用並查集在維護這個資訊,也就是字首和,字首和就是前i個月收入的錢,那麼對於任意一行資料 s t v 都有 sum s sum t v 然後在並查集的時候,查詢父親節點的時候,將sum值累...

HNOI2005 狡猾的商人

刁奼接到乙個任務,為稅務部門調查一位商人的賬本,看看賬本是不是偽造的。賬本上記錄了n個月以來的收入情況,其中第i 個月的收入額為ai i 1,2,3 n 1,n 當 ai大於0時表示這個月盈利ai 元,當 ai小於0時表示這個月虧損ai 元。所謂一段時間內的總收入,就是這段時間內每個月的收入額的總和...