NOIp2011提高組
題目描述
麗江河邊有n 家很有特色的客棧,客棧按照其位置順序從 1 到n 編號。每家客棧都按照某一種色調進行裝飾(總共 k 種,用整數 0 ~ k-1 表示),且每家客棧都設有一家咖啡店,每家咖啡店均有各自的最低消費。
兩位游客一起去麗江旅游,他們喜歡相同的色調,又想嘗試兩個不同的客棧,因此決定分別住在色調相同的兩家客棧中。晚上,他們打算選擇一家咖啡店喝咖啡,要求咖啡店位於兩人住的兩家客棧之間(包括他們住的客棧),且咖啡店的最低消費不超過 p 。
他們想知道總共有多少種選擇住宿的方案,保證晚上可以找到一家最低消費不超過 p元的咖啡店小聚。
輸入輸出格式
輸入格式:
輸入文件hotel.in,共n+1 行。
第一行三個整數n ,k ,p,每兩個整數之間用一個空格隔開,分別表示客棧的個數,色調的數目和能接受的最低消費的最高值;
接下來的n 行,第 i+1 行兩個整數,之間用一個空格隔開,分別表示 i 號客棧的裝飾色調和i 號客棧的咖啡店的最低消費。
輸出格式:
輸出文件名為hotel.out 。
輸出只有一行,一個整數,表示可選的住宿方案的總數。
輸入輸出樣例
輸入樣例#1:
5 2 3 0 5 1 3 0 2 1 4 1 5
輸出樣例#1:
3
說明
【輸入輸出樣例說明】 
2 人要住同樣色調的客棧,所有可選的住宿方案包括:住客棧①③,②④,②⑤,④⑤,但是若選擇住4 、5 號客棧的話,4 、5 號客棧之間的咖啡店的最低消費是4 ,而兩人能承受的最低消費是3 元,所以不滿足要求。因此只有前 3 種方案可選。
【數據范圍】
對於30% 的數據,有 n ≤100;
對於50% 的數據,有 n ≤1,000;
對於100%的數據,有 2 ≤n ≤200,000,0<k ≤50,0≤p ≤100 , 0 ≤最低消費≤100。
思路
其實剛開始讓我做這道題目的時候我是想了很多錯誤的算法和復雜度O(N^2)甚至是O(N^3)的算法的。⊙﹏⊙
觀察100%的數據可以發現,想要AC必須要用時間復雜度一維的算法,研究CODEVS和LG上的題解分析,“野菜湯”同學的解法實在是妙,題解有些的詳細,當不愧為OI業界良心。姑且讓我把他的思路轉述,留作后人參考。
首先我們看,當找到一個旅店,在右邊,若是其左邊有一個符合要求的咖啡店,那么再往左邊看,如果有一個顏色相同的旅店,那么就算是一種住宿方法了,那么如果以這個右邊的旅店作為對應點,將所有在左邊而且顏色與之相同的旅店數相加,就能得出很多種住宿方法了。那么用這個辦法,用所有的對應點對應過去,就能最快的時間內找出所用的酒店了。
可思想說起來簡單,程序想要寫的精簡也是不那么容易的。先對程序內的變量做些解釋:
a數組是記錄同一種顏色中的酒店所出現的最后一次的位置;b數組記錄同一種顏色的酒店的出現次數,而c數組則是臨時記錄當前同樣顏色的酒店出現的次數,也就是為找對應點而進行的臨時記錄。
那么,通過使用上述方法,僅僅需要一個for循環,即可解決問題,當時讀入,立即處理,這才是此題解的精髓所在,遠勝於其他題解。
然而數學好是怎么樣的一種體驗呢?
我不會告訴你這題可以用排列組合的方法就能完美AC。
總的解數= 所有色調相同的客棧兩兩相配的總數量 - 因咖啡館價格問題而不能相配的數量 。 (這里是組合型)
var i,j,k,m,n,p,q,sum:longint; a,b,c:array[0..100] of longint; begin read(n,k,p); for i:=1 to n do begin readln(k,q); if q<=p then m:=i; {如果咖啡店的最低消費地於標准,那么記錄其位置} if (m>=a[k]) then c[k]:=b[k]; {如果在當前顏色的酒店之前有出現過同樣顏色的酒店那么記錄當前同種顏色的酒店的出現次數} a[k]:=i;{記錄同樣顏色的酒店最后一次的出現位置} sum:=sum+c[k]; {每一個酒店都可以作為對應點,所以不需要再去加上任何的判斷,記錄住宿的方法} inc(b[k]);{記錄出現次數的總數} end; writeln(sum); end.
