還是太弱了…這道題拿到手上後完全沒有能夠在規定時間內解決的思路。不過還好,大體思路是對的:
首先預處理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
) 。對於這道題而言,可以這樣定義:
有沒有感覺這和st表的定義很像?事實上,st表就是用的倍增的思想。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開了車,需要單獨計算
列舉時,我們將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...