【問題描述】
奶牛在熊大媽的帶領下排成了一條直隊。
顯然,不同的奶牛身高不一定相同……
現在,奶牛們想知道,如果找出一些連續的奶牛,要求最左邊的奶牛 a 是最矮的,最右
邊的 b 是最高的,且 b 高於 a 奶牛,且中間如果存在奶牛,則身高不能和 a、b 奶牛相同,
問這樣的一些奶牛最多會有多少頭。
從左到右給出奶牛的身高,請告訴它們符合條件的最多的奶牛數(答案可能是零、二,
但不會是一)。
【輸入格式】
第一行乙個數 n(2<=n<=100000),表示奶牛的頭數。
接下來 n 個數,每行乙個數,從上到下表示從左到右奶牛的身高(1<=身高
<=maxlongint)。
【輸出格式】
一行,表示最多奶牛數。
【輸入樣例】tahort.in51
2341
【輸出樣例】tahort.out
4【 樣例解析 】
取第 1 頭到第 4 頭奶牛,滿足條件且為最多。
這道題的思路如下:我們可以首先找到整個區間內最高的牛所在的位置和最矮的牛所在的位置。這樣的話,答案區間就不可能越過這兩頭牛了,之後將區間分開遞迴求解即可。如果高的牛(maxn)在矮的牛(minn)前面,那麼遞迴搜尋
(l,maxn),(maxn+1,minn-1),(minn,r) ,如果矮的牛在高的牛前面,那麼我們直接用maxn-minn+1更新答案,之後遞迴搜尋(l,minn-1),(maxn+1,r)即可。
這樣的話問題就轉化成了如何快速求任意一段區間內的最大最小值的位置。這是乙個典型的rmq問題,我們選擇使用st表解決。既然只求最大最小值的位置,那麼我們就可以不使用st表存值,這樣不僅好寫而且時間還短。具體的做法就是我們自定義函式來比較編號,每次比較大小結束之後記錄當前區間內最大(小)值的位置即可。這樣每次遞迴訪問的時候,我們甚至可以做到o(1)。
這道題有很多地方還是非常坑的,比如說你寫乙個十分正確的rmq在lemon或者本機上執行都會導致re,據說可能是因為遞迴層數過多而爆棧,這個自己本人除錯也調不出來,你只會看到程式在輸入所有資料之後報錯。可以使用vijos代測,但是我的程式前幾次提交全部tle,結果最後採用了乙個優化,就是如果遞迴的區間長度小於當前的答案就直接返回無需搜尋。但還是不行……最後發現是因為開了全域性變數的緣故,開成區域性變數就過了……蒟蒻至今搞不明白是為什麼。
最後上一下**吧。
#include#include#include
#include
#include
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
using
namespace
std;
const
int n = 100005,m = 18
;typedef
long
long
ll;int
n,h[n],max1[n][m],min1[n][m],ans1;
intread()
while(ch >= '
0' && ch <= '9'
)
if(last == '
-') ans = -ans;
return
ans;
}int fmax(int c,int d)//
自定義比較編號的函式
int fmin(int c,int
d)void ask(int l,int
r)
else
}int
main()
int q =log2(n);
rep(j,
1,q)
//st表求最大最小值
} ask(
1,n);
printf(
"%d\n
",ans1);
return0;
}
高手訓練 RMQ 奶牛排隊
第一題由於過水,就沒寫awa 大概就是這樣了。題意就是求乙個最長的區間使得區間的左邊是它的最小值,區間右邊是他的最大值 第乙個想法肯定是暴力列舉啦awa 但是這個是o n 3 的,絕對的不可過awa 思考性質awa 發現我們列舉每個區間的左右端點,其實有大量的不合法的計算的 也就是沒有用的列舉。考慮...
奶牛排序 cow sort 置換群
農夫john準備把他的 n 1 n 10,000 頭牛排隊以便於行動。因為脾氣大的牛有可能會搗亂,john想把牛按脾氣的大小排序。每一頭牛的脾氣都是乙個在1到100,000之間的整數並且沒有兩頭牛的脾氣值相同。在排序過程中,john可以交換任意兩頭牛的位置。因為脾氣大的牛不好移動,john需要x y...
USACO 奶牛排隊
題目 給出乙個只含有1,2,3的數字序列,問最少交換多少次才能將之變為遞增數列。解 注意到只有1,2,3,我們只要將1,3交換到自己的應在位置上那麼排序就已經完成了。需要交換的有幾種,記 a x,y 表示x在應該是y的位置上的 a i 的個數,那麼我們優先交換a 1,3 和a 3,1 裡的數字,一次...