Hər indeks üçün , RMinQ(s_{i+1}, ..., s_k) > s_i şərti təmin edilən maksimum k~(i \le k \le n) indeksini tapırıq. Bunu ikili axtarışla həyata keçirmək olar. Bundan sonra, tələb olunan indeks , i \le j \le k olan intervalda RMaxQ(s_i, ..., s_k) dəyərinin çatıldığı mövqe olaraq təyin edilir.
Beləliklə, hər indeks üçün maksimum mümkün olan indeks tapılmalıdır və tapılan bütün cütlüklər arasında ən böyük fərqi j - i tapırıq.
Nümunə
Üçüncü nümunəni nəzərdən keçirək.
Tutaq ki, i = 2~(s_2 = 4). Burada RMinQ(s_{i+1}, ..., s_k) > 4 şərtini təmin edən k = 7 maksimum indekdir. RMaxQ(s_3, ..., s_7) dəyəri indeks j = 6 üzərində əldə edilir.
Alqoritmin həyata keçirilməsi
Daimlər və massivləri elan edirik.
#define MAX 50010
#define LOGMAX 16
int dp_max[MAX][LOGMAX], dp_min[MAX][LOGMAX];
int a[MAX];Build_RMQ_Array funksiyası sürətli minimum () və maksimum () sorğular üçün cədvəllərini qurur:
dp\_min[i][j] mövqeyindən başlayaraq uzunluğu 2^j olan aralıqdakı minimum dəyəri saxlayır.
dp\_max[i][j] mövqeyindən başlayaraq uzunluğu 2^j olan aralıqdakı maksimum dəyərə malik elementin indeksini saxlayır.
void Build_RMQ_Array(int *b)
{
int i, j;
for (i = 1; i <= n; i++)
{
dp_min[i][0] = b[i];
dp_max[i][0] = i;
}
for (j = 1; 1 << j <= n; j++)
for (i = 1; i + (1 << j) - 1 <= n; i++)
{
if (b[dp_max[i][j - 1]] > b[dp_max[i + (1 << (j - 1))][j - 1]])
dp_max[i][j] = dp_max[i][j - 1];
else
dp_max[i][j] = dp_max[i + (1 << (j - 1))][j - 1];
dp_min[i][j] =
min(dp_min[i][j - 1], dp_min[i + (1 << (j - 1))][j - 1]);
}
}RangeMaxQuery funksiyası aralığındakı maksimum elementin indeksini tapır.
int RangeMaxQuery(int i, int j)
{
int k = 0;
while ((1 << (k + 1)) <= j - i + 1) k++;
if (a[dp_max[i][k]] > a[dp_max[j - (1<<k) + 1][k]])
return dp_max[i][k];
else
return dp_max[j - (1<<k) + 1][k];
}RangeMinQuery funksiyası aralığında minimum dəyəri tapır.
int RangeMinQuery(int i, int j)
{
int k = 0;
while ((1 << (k + 1)) <= j - i + 1) k++;
return min(dp_min[i][k],dp_min[j - (1<<k) + 1][k]);
}BinSearch funksiyası ikili axtarışla [Left; Right] intervalında a[Left]-dən böyük olan elementlər Left + 1 və arasında olan ən böyük indeksini tapır.
int BinSearch(int Left, int Right)
{
int MinValue = a[Left++];
if (RangeMinQuery(Left,Right) > MinValue) return Right;
while (Right > Left)
{
int Middle = (Left + Right) / 2;
if (RangeMinQuery(Left,Middle) > MinValue)
Left = Middle + 1;
else
Right = Middle;
}
if (dp_min[Left][0] <= MinValue) Left--;
return Left;
}Proqramın əsas hissəsi. Ardıcıllıqla testləri işləyirik.
while(scanf("%d",&n) == 1)
{
for(i = 1; i <= n; i++) scanf("%d",&a[i]);və massivləri qururuq.
Build_RMQ_Array(a);Hər indeks üçün:
BinSearch(i, n) istifadə edərək, i + 1 və aralığında bütün elementlərin -dən böyük olduğu ən böyük indeksi tapırıq;
aralığında maksimum dəyərin çatıldığı indeks -ni tapırıq.
j - i ən böyük fərq olduğunu yoxlayırıq.
res = 0;
for(i = 1; i <= n; i++)
{
k = BinSearch(i, n);
j = RangeMaxQuery(i,k);
if (j - i > res) res = j - i;
}Cavabı çıxarırıq. Əgər res = 0, o zaman çıxarılır.
if (res == 0) res = -1;
printf("%d\n",res);
}