Mutasiya#4973

Mutasiya (Həll təhlili)

Genlərin permutasiyası elə yerinə yetirilməlidir ki, eyni genlər yan-yana yerləşsin. Eyni zamanda yerinə yetirilən əməliyyatların sayını minimallaşdırmaq lazımdır.

Hər təbii ədəd a_i üçün [s_i; e_i] intervallını təyin edək, burada s_i – a_i-nin ilk dəfə rast gəlindiyi pozisiyadır və e_i – a_i-nin sonuncu dəfə rast gəlindiyi pozisiyadır.

Tutaq ki, – kəsişməyən ən böyük mümkün interval sayıdır. Bu dəyəri "tətbiq seçimi" alqoritmi ilə tapmaq olar, bu da o deməkdir ki, qalan intervallardan hər biri seçilmişlərdən ən azı biri ilə kəsişir. Bundan sonra bu intervallara uyğun gələn genlər üzərində təsvir edilmiş prosesi icra etmək lazımdır.

Əgər – qurulmuş intervalların ümumi sayıdır. Onda məsələnin cavabı k - res dəyəri olacaq.

Misal

Göstərilən misal üçün intervallar belə olacaq (pozisiyaların nömrələnməsi sıfırdan başlayır):

Intervalı sonuna görə çeşid edək:

[0; 4], [3; 5], [1; 6], [7; 7], [8; 8]

Kəsişməyən maksimum interval sayı -ə bərabərdir. Məsələn, [0; 4], [7; 7], [8; 8] intervallarını seçmək olar. Qalan intervallara uyğun gələn genlər üçün məsələnin şərtində təsvir olunan prosedur yerinə yetirilməlidir. Belə genlər və -dür. İki permutasiya, məsələn, aşağıdakı kimi həyata keçirilə bilər:

Alqoritmin həyata keçirilməsi

Tutaq ki, – giriş ardıcıllığında ola bilən maksimum genom sayıdır.

#define MAX 100001

Cütlər cədvəli (əvvəl, sonra) intervalları [s_i; e_i] saxlayır.

vector<pair<int, int> > v;
int s[MAX], e[MAX];

Giriş məlumatlarını oxuyuruq. s_i = -1, e_i = -1 ilə başladırıq.

scanf("%d", &n);
memset(s, -1, sizeof(s));
memset(e, -1, sizeof(e));

for (i = 0; i < n; i++)
{
  scanf("%d", &x);

Əgər sayı ilk dəfə rast gəlinirsə, onun pozisiyasını giriş ardıcıllığında s_x-da qeyd edirik.

  if (s[x] == -1) s[x] = i;

Əgər sayı ilk dəfə rast gəlinmirsə, onun pozisiyasını e_x-da qeyd edirik, yəni -ın sonuncu rast gəlinmə pozisiyası.

  if (i > e[x]) e[x] = i;
}

Bütün qurulan intervalları cütlər cədvəlində -da saxlayırıq.

for (i = 1; i <= n; i++) // sayılar 1..n
  if (s[i] != -1) v.push_back(make_pair(e[i], s[i]));

İntervalar cədvələ tərsinə daxil edilir (şəkli [e_i; s_i] kimi), belə ki, cədvəlin standart çeşidlənməsi sonlarına görə artma qaydasında olur.

sort(v.begin(), v.end());

Maksimum kəsişməyən interval sayını tapırıq.

i = res = 0;
while (i < v.size())
{

-ci intervalı kəsişməzlər çoxluğuna daxil edirik. dəyişən bu intervalın sonunu saxlayır (onu cari interval adlandıraq).

  res++; temp = v[i++].first; // son

Növbəti intervalın başlanğıcı cari intervalın sonunda az olduğu halda, bu intervalı keçirik, çünki o, cari ilə kəsişir.

  while (i < v.size() && v[i].second < temp) i++;
}

Cavabı çap edirik.

printf("%d\n", v.size() - res);