NOIP 2012 Senior 3 開車旅行

2021-08-03 13:32:09 字數 3195 閱讀 4119

還是太弱了…這道題拿到手上後完全沒有能夠在規定時間內解決的思路。不過還好,大體思路是對的:

首先預處理a、b在每個地方開一次車到達的地方。對於第一問,列舉a出發的位置,對於第二問,直接計算就行了。計算的方法就是挨著推,直到滿足題目中結束旅行的條件。很明顯,預處理的時間複雜度為o(

n2) ,計算的時間複雜度為o(

n),因此整個程式的時間複雜度就為o(

n2+n

2+nm

) ,平方級的,按理說還能過個50~70分,但是可能比賽時計算比例那裡寫錯了,最後只有35分。

這個題的思路就是這樣,我們要做的就是將上面的兩個操作至少優化到o(

nlog

n),幸運的是,這種演算法是存在的。對於操作1,我們可以用一棵平衡樹以o(

logn

) 的時間複雜度完成操作,但我連平衡樹都沒有學過= =。幸運的是,stl有乙個現成的平衡樹set,使用它就已足夠滿足我們的要求了。

由於旅行只能從左往右走,因此我們只能從右往左向set中新增結點。假設有5座城市1,2,3,4,5,我們要計算a、b各自從3出發到達的下乙個城市:

3

/ \4 5

這裡假設4比3低,5比3高,那麼樹將會是以上這樣。

我們可以使用set的find方法找到3的位置,然後對迭代器進行++,–,就能找到4,5了。

那麼到底a該走**,b該走**呢?假設我們要計算1:

1

/ \3 5 //這棵樹是我亂編的

/ \

4 2

所以我們現在知道的是可能的答案為3,4,5,2,即向左擴充套件2個結點,向右擴充套件2個結點(想一想,為什麼)。我們對這四個結點的進行排序,第0個就是b的目的地,第1個就是a的目的地。當然,如果a沒有目的地,就不要改a。

對於計算這個操作,我們可以使用倍增的思想。之前我們一次走一步,時間複雜度為o(

n)。倍增的思想就是花上o(

nlog

n)的時間進行預處理,使每次的查詢時間將為o(

logn

) 。對於這道題而言,可以這樣定義:

next[k][i]代表從i出發,ab開了2^k輪車後到達的位置(一輪指ab先後開了一次車)

disa[k][i]代表從i出發,ab開了2^k輪車後a走的里程

disb[k][i]代表從i出發,ab開了2^k輪車後b走的里程

如果遇到最後只有a開了車,需要單獨計算

有沒有感覺這和st表的定義很像?事實上,st表就是用的倍增的思想。

列舉時,我們將k從大到小進行列舉(想一想,為什麼不能從小到大)。如果開2^k輪車後能走到乙個地方,則開,否則k--。k最終列舉到0,這毋庸置疑,那k從**開始列舉呢?我們可以從可能的極大值開始。因為如果k很大,肯定是開不到的,只是浪費一點時間而已。

最後,我們根據初始化的資訊推算即可,詳見**。

參考**

#include 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

std::cin;

using

std::cout;

using

std::endl;

#define for(x, f, t) for(int x = (f); x <= (t); x++)

inline

int readin()

const

int maxn = 100005;

const

int maxm = 100005;

int n,m;

struct city

bool

operator

< (const city& b) const

} cities[maxn];

int start[maxm];

int x[maxm];

int height;

struct sub //用於初始化

bool

operator

<(const sub& b) const

x[0]=readin();

m=readin();

for(i, 1, m)

}void init()

it++;

}if(it!=des.end())

}height = cities[i].height;

std::sort(subs, subs+ncmp);

nextb[i] = subs[0].destination.index;

if(i<=n-2) nexta[i] = subs[1].destination.index;

}}void go(int from, int x, long

long& lengtha, long

long& lengthb)

}int last = nexta[from]; //看看a還能不能走

if(!last) return;

int lastdis = std::abs(cities[last].height - cities[from].height);

if(lastdis <= x) lengtha+=lastdis;

}void run()

for(int i = 1; i <= maxindex - 1; i++) //初始化開2^k輪的情況

}//solve1

long

long ansa=1e15;

long

long ansb=0;

int ans = 0;

for(int i = 1; i <= n; i++)

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

//solve2

for(int i = 1; i <= m; i++)

}int main()

NOIP 2014 Senior 2 聯合權值

思路1 很明顯,題目給定的是一棵樹,所以想到使用樹形dp,所以首先,將無根樹轉換成有根樹。可以記錄乙個結點的所有孫結點 子結點的子結點 的最大權值以及它們的權值和 當然要求餘了 對於某個結點和它的所有孫子結點來說,它們的最大聯合權值就是孫子結點的最大權值乘以該結點的權值,聯合權值和就是孫子結點與該結...

Noip2014senior複賽 飛揚的小鳥

noip2014senior複賽 飛揚的小鳥 問題描述 1.遊戲介面是乙個長為 n,高為 m 的二維平面,其中有 k 個管道 忽略管道的寬度 2.小鳥始終在遊戲介面內移動。小鳥從遊戲介面最左邊 任意整數高度位置出發,到達遊戲介面最右邊時,遊戲完成。3.小鳥每個單位時間沿橫座標方向右移的距離為 1,豎...

NOIP2012 T3開車旅行 set 倍增

70分做法 先預處理出所有點的最近和次近 o n 2 一遍就ok 然後暴力求出每個解 o nm by siriusren include include include define inf 0x3fffffff using namespace std int n,x,rech 0x3fffffff...