這個題目還是值得思考的.
看到這個題目, 大家應該都想到了這樣乙個思路, 就是把每個點能夠達到的最近的和次近的點都預處理出來, 然後跑就可以了, 現在問題就是難在這個預處理上面, 我們應該如何做呢? 觀察到, 近的概念是兩點之間的海拔距離最小, 所以我們可以將海拔距離從後往前(畢竟你只能往你後面的地方走嘛...), 扔進乙個可以維護大小關係的資料結構中, 不妨設當前點海拔進入這個資料結構後位置為\(k\), 那麼我們只需要比較位置為\(k - 1\), \(k - 2\), \(k + 1\), \(k + 2\)的四個數就可以了, 大家可以自己在紙上分類討論一下, 這裡就不做過多的闡述了. 現在我們只需要知道這個資料結構就可以了, 大家想一想, 有什麼資料結構可以快速的找到某個數排序後的位置呢? 平衡樹, 查詢和插入的複雜度都為\(\log_ \)了, 這樣我們就可以快速尋找了, 當然, 因為有重複結構, 所以用stl中的\(multiset\)是比較好的一種辦法(其實是我不會雙向鍊錶), 這樣我們就將比較難想的預處理部分弄出來了.
當然, 想完了預處理後我們就可以想接下來怎麼走了. 比較快速的方法是倍增, \(f[i][j][opt]\)表示當前位置為\(i\), 已經走了\(2 ^j\)天, \(opt\)為1時代表從\(i\)位置開始走, 第乙個走的是b所走到的位置, 那麼\(opt\)是\(0\)時就是a了. \(disa[i][j][opt]\)代表在第\(i\)位出發, 走了\(2 ^ j\)天, \(opt\)為1代表從\(i\)開始走, b先出發, 在這段時間中a走的距離, opt為\(0\)自己推一下吧, 實在是不想打了, \(disb[i][j][opt]\)也自己照著看一下吧. 我們在預處理出每個點的最近點和次近點後, 就可以處理出來了.
至此, 預處理完畢, 剩下的**中會說到的.
#include #include #include #include #define n 100005
using namespace std;
int n, x0, m, f[n][22][2], disa[n][22][2], disb[n][22][2], bin;
struct node
} ht[n];
multisets;
multiset:: iterator it;
inline int read()
while(c >= '0' && c <= '9')
return x * w;
}inline void get_ans(int s, int &dist_a, int &dist_b, int limit)
}inline long long abs(long long x)
inline void init()
else
//注意, 這裡由於前後海拔差相同的話取海拔較低的, 所以有的地方有等於號, 有的地方沒有, 希望大家能夠自己好好去想一下為什麼, 有問題可以私信我(反正我不會回答的(手動刪除)).
f[i][0][0] = ato; f[i][0][1] = bto;
disa[i][0][0] = abs(ht[ato].h - ht[i].h); disb[i][0][0] = 0;
disb[i][0][1] = abs(ht[bto].h - ht[i].h); disa[i][0][1] = 0;
} for(int i = 1; i <= n; i++)//由於上面並沒有討論到a, b都走過了的情況, 只討論了a和b單獨走的情況, 故在這裡要處理一下.
for(int j = 2; j <= 20; j++)
for(int i = 1; i <= n; i++) }
int main()
ht[0].h = 2e9 + 7; ht[n + 1].h = -(2e9 + 7); ht[0].id = 0; ht[n + 1].id = n + 1;
//我取2147483647爆掉了, 調了整整一上午, 所以取極值的時候需要注意一下
s.insert(ht[0]); s.insert(ht[0]); s.insert(ht[n + 1]); s.insert(ht[n + 1]);
//插入兩個極小值和極大值代表我們在找到位置k的時候, 他前後總會至少有兩個點, 免去了分類討論的冗雜
init(); //預處理
x0 = read(); m = read();
int id = 0;
double ans = 1e16;
for(int i = 1; i <= n; i++)//列舉每乙個點為起點時的比例
else if(ans == 1e14 && ht[i].h > ht[id].h) id = i;
} else
else if(res == ans && ht[i].h > ht[id].h) id = i;
} }printf("%d\n", id);
for(int i = 1; i <= m; i++)
return 0;
}
Luogu1081 開車旅行
巨長的倍增題.顯然這是沒有什麼決策的,選擇方案都是固定的 這可以考慮倍增跳,每個位置上跳到的位置是可以通過查前驅後繼解決的 有兩種方式 一種是平衡樹搞法,倒著做查完了插入 另一種是先排序建乙個鍊錶,查完了刪除 都是可以通過加哨兵節點來搞的,結果我只想到了 set 亂搞,就寫了很長 預處理完就可做了 ...
倍增 luogu1081開車旅行
傳送門 倍增神題?細節超級多 其實思路很簡單 對於每個點,a和b要開去的目的地是固定的,所以就想到了倍增 開三個倍增陣列,t i j k 代表k從i開車走2 j天走到的那個城市 f是a走的路程,g是b走的路程 0代表a,1代表b 對於預處理,一開始怎麼想怎麼是n 2的 後來自己yy了一下覺得每次so...
luogu p1081 開車旅行
傳送門 此題為複雜細節題,無法總結題意,所以給出原題 小 text 和小 text 決定利用假期外出旅行,他們將想去的城市從 1 到 n 編號,且編號較小的城市在編號較大的城市的西邊,已知各個城市的海拔高度互不相同,記城市 i 的海拔高度為 h i 城市 i 和城市 j 之間的距離 d 恰好是這兩個...