Cim və göydələnlər#11720

Cim və göydələnlər (Həll təhlili)

Tutaq ki, eyni hündürlükdə bloklardan "divarlar" qururuq.

Cütlük "dəhliz" əmələ gətirir, əgər bu divarların arasında daha hündür divar yoxdursa. Məsələnin həlli üçün monotondan ibarət stekdən istifadə edəcəyik. Stek cütlərini saxlayır (qiymət, say):

Yəni:

Məsələn, cari rəqəm a = 5-ə bərabər olsun və əvvəllər bu rəqəm dəfə görülmüş olsun (beləliklə, mövcud anda a = 5-ci rəqəm dördüncü dəfədir görünür). Tutaq ki, bu rəqəmlərin arasında yalnız daha kiçik elementlər var. O zaman yeni indeks cütləri sayı, harada ki cari indeksdir və şərt h_i = h_j = a belədir, -ə bərabər olacaq.

Növbəti h_i rəqəmi işlənərkən:

Nümunə

İlk testi nəzərdən keçirək.

Alqoritmin həyata keçirilməsi

Giriş məlumatlarını oxuyuruq.

scanf("%d", &n);
vector<int> v(n);
for (i = 0; i < n; ++i)
  scanf("%d", &v[i]);

dəyişənində tapılan indeks cütlərinin sayını saxlayacağıq.

res = 0;

Cütlər stekini elan edək.

stack<pair<int, int>> st;

Massivin bütün rəqəmlərini ardıcıl emal edirik.

for (i = 0; i < v.size(); i++)
{

Stekin zirvəsində -dən kiçik olan bir rəqəm olduğu müddətcə, bu rəqəmi stekdən çıxarırıq.

  while (!st.empty() && st.top().first < v[i])
    st.pop();

Əgər stekin zirvəsində -yə bərabər olan bir rəqəm varsa və bu rəqəm əvvəllər dəfə görünüb (bu dəyər st.top().second-də saxlanılır), o zaman cavabımız -i qədər artırırıq. Bundan sonra isə -nin görünmə sayını x + 1-ə yeniləyirik.

  if (!st.empty() && v[i] == st.top().first)
  {
    res += st.top().second;
    st.top().second += 1;
  }
  else

Əgər rəqəmi ilk dəfə görünürsə, o zaman stekə (v[i], 1) cütünü əlavə edirik.

    st.push({ v[i], 1 });
}

Cavabı çıxarırıq.

printf("%lld\n", res);